javascript
剑指Spring源码(一)
Spring,相信每個(gè)Java開(kāi)發(fā)都用過(guò),而且是每天都在用,那強(qiáng)大又神秘的IoC,AOP,讓我們的開(kāi)發(fā)變得越來(lái)越簡(jiǎn)單,只需要一個(gè)注解搞定一切,但是它內(nèi)部到底是什么樣子的呢?跟著我,一起探究Spring源碼把。
寫(xiě)在前面的話:Spring項(xiàng)目距今已有15年左右的歷史了,是眾多Java大神們的杰作,由于我個(gè)人水平有限,時(shí)間有限,不保證我說(shuō)的全部都是正確的,但是我可以保證每一句話都是反復(fù)推敲,經(jīng)過(guò)驗(yàn)證,絕沒(méi)有復(fù)制粘貼。當(dāng)然在這里,也不可能把每個(gè)方法都進(jìn)行深層次的分析,只能把重點(diǎn)集中在重要的方法上,有些(其實(shí)是絕大部分)只能采取黑盒理論,即:不去探究方法內(nèi)部到底做了什么,只大概的知道執(zhí)行這個(gè)方法后發(fā)生了什么。
本文中采用的Spring版本是5.0.0
由于現(xiàn)在JavaConfig風(fēng)格+注解的方式來(lái)使用Spring,是Spring官方主推的,也是現(xiàn)在的主流方式,所以我們從這里出發(fā):
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);讓我們先來(lái)看看AnnotationConfigApplicationContext的關(guān)系圖:
可以看到這個(gè)關(guān)系夠復(fù)雜的,我們現(xiàn)在完全不需要特意全部記住,只要有一個(gè)大概的印象就可以了,后面隨著源碼分析的深入,自然而然會(huì)記住其中的一些關(guān)系。
創(chuàng)建AnnotationConfigApplicationContext對(duì)象,首先會(huì)跑到這里:
//根據(jù)參數(shù)類型可以知道,其實(shí)可以傳入多個(gè)annotatedClasses,但是這種情況出現(xiàn)的比較少public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {//調(diào)用無(wú)參構(gòu)造函數(shù),會(huì)先調(diào)用父類GenericApplicationContext的構(gòu)造函數(shù)//父類的構(gòu)造函數(shù)里面就是初始化DefaultListableBeanFactory,并且賦值給beanFactory//本類的構(gòu)造函數(shù)里面,初始化了一個(gè)讀取器:AnnotatedBeanDefinitionReader read,一個(gè)掃描器ClassPathBeanDefinitionScanner scanner//scanner的用處不是很大,它僅僅是在我們外部手動(dòng)調(diào)用 .scan 等方法才有用,常規(guī)方式是不會(huì)用到scanner對(duì)象的this();//把傳入的類進(jìn)行注冊(cè),這里有兩個(gè)情況,//傳入傳統(tǒng)的配置類//傳入bean(雖然一般沒(méi)有人會(huì)這么做//看到后面會(huì)知道spring把傳統(tǒng)的帶上@Configuration的配置類稱之為FULL配置類,不帶@Configuration的稱之為L(zhǎng)ite配置類//但是我們這里先把帶上@Configuration的配置類稱之為傳統(tǒng)配置類,不帶的稱之為普通beanregister(annotatedClasses);//刷新refresh();}這個(gè)方法第一眼看上去,很簡(jiǎn)單,無(wú)非就是三行代碼,但是這三行代碼包含了大千世界。
我們先來(lái)為構(gòu)造方法做一個(gè)簡(jiǎn)單的說(shuō)明:
這是一個(gè)有參的構(gòu)造方法,可以接收多個(gè)配置類,不過(guò)一般情況下,只會(huì)傳入一個(gè)配置類。
這個(gè)配置類有兩種情況,一種是傳統(tǒng)意義上的帶上@Configuration注解的配置類,還有一種是沒(méi)有帶上@Configuration,但是帶有@Component,@Import,@ImportResouce,@Service,@ComponentScan等注解的配置類,在Spring內(nèi)部把前者稱為Full配置類,把后者稱之為L(zhǎng)ite配置類。在本源碼分析中,有些地方也把Lite配置類稱為普通Bean。
我們先來(lái)看一下第一行代碼:通過(guò)this()調(diào)用此類無(wú)參的構(gòu)造方法,代碼會(huì)跑到下面:
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {//注解bean定義讀取器,主要作用是用來(lái)讀取被注解的了beanprivate final AnnotatedBeanDefinitionReader reader;//掃描器,它僅僅是在我們外部手動(dòng)調(diào)用 .scan 等方法才有用,常規(guī)方式是不會(huì)用到scanner對(duì)象的private final ClassPathBeanDefinitionScanner scanner;/*** Create a new AnnotationConfigApplicationContext that needs to be populated* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.*/public AnnotationConfigApplicationContext() {//會(huì)隱式調(diào)用父類的構(gòu)造方法,初始化DefaultListableBeanFactory//初始化一個(gè)Bean讀取器this.reader = new AnnotatedBeanDefinitionReader(this);//初始化一個(gè)掃描器,它僅僅是在我們外部手動(dòng)調(diào)用 .scan 等方法才有用,常規(guī)方式是不會(huì)用到scanner對(duì)象的this.scanner = new ClassPathBeanDefinitionScanner(this);} }首先映入眼簾的是reader和scanner,無(wú)參構(gòu)造方法中就是對(duì)reader和scanner進(jìn)行了實(shí)例化,reader的類型是AnnotatedBeanDefinitionReader,從字面意思就可以看出它是一個(gè) “打了注解的Bean定義讀取器”,scanner的類型是ClassPathBeanDefinitionScanner,其實(shí)這個(gè)字段并不重要,它僅僅是在我們外面手動(dòng)調(diào)用.scan方法,或者調(diào)用參數(shù)為String的構(gòu)造方法,傳入需要掃描的包名,才會(huì)用到,像我們這樣傳入配置類是不會(huì)用到這個(gè)scanner對(duì)象的。
AnnotationConfigApplicationContext類是有繼承關(guān)系的,會(huì)隱式調(diào)用父類的構(gòu)造方法:
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {private final DefaultListableBeanFactory beanFactory;public GenericApplicationContext() {this.beanFactory = new DefaultListableBeanFactory();} }這個(gè)代碼很簡(jiǎn)單,就是初始化了DefaultListableBeanFactory。
我們?cè)賮?lái)看看DefaultListableBeanFactory的關(guān)系圖:
DefaultListableBeanFactory是相當(dāng)重要的,從字面意思就可以看出它是一個(gè)Bean的工廠,什么是Bean的工廠?當(dāng)然就是用來(lái)生產(chǎn)和獲得Bean的。
讓我們把目光回到AnnotationConfigApplicationContext的無(wú)參構(gòu)造方法,讓我們看看Spring在初始化AnnotatedBeanDefinitionReader的時(shí)候做了什么:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {this(registry, getOrCreateEnvironment(registry));}這里的BeanDefinitionRegistry當(dāng)然就是AnnotationConfigApplicationContext的實(shí)例了,這里又直接調(diào)用了此類其他的構(gòu)造方法:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");Assert.notNull(environment, "Environment must not be null");this.registry = registry;this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}讓我們把目光移動(dòng)到這個(gè)方法的最后一行,進(jìn)入registerAnnotationConfigProcessors方法:
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {registerAnnotationConfigProcessors(registry, null);}這又是一個(gè)門面方法,再點(diǎn)進(jìn)去,這個(gè)方法的返回值Set,但是上游方法并沒(méi)有去接收這個(gè)返回值,所以這個(gè)方法的返回值也不是很重要了,當(dāng)然方法內(nèi)部給這個(gè)返回值賦值也不重要了。由于這個(gè)方法內(nèi)容比較多,這里就把最核心的貼出來(lái),這個(gè)方法的核心就是注冊(cè)Spring內(nèi)置的多個(gè)Bean:
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); }判斷容器中是否已經(jīng)存在了ConfigurationClassPostProcessor Bean
如果不存在(當(dāng)然這里肯定是不存在的),就通過(guò)RootBeanDefinition的構(gòu)造方法獲得ConfigurationClassPostProcessor的BeanDefinition,RootBeanDefinition是BeanDefinition的子類:
3.執(zhí)行registerPostProcessor方法,registerPostProcessor方法內(nèi)部就是注冊(cè)Bean,當(dāng)然這里注冊(cè)其他Bean也是一樣的流程。
BeanDefinition是什么,顧名思義,它是用來(lái)描述Bean的,里面存放著關(guān)于Bean的一系列信息,比如Bean的作用域,Bean所對(duì)應(yīng)的Class,是否懶加載,是否Primary等等,這個(gè)BeanDefinition也相當(dāng)重要,我們以后會(huì)常常和它打交道。
registerPostProcessor方法:
private static BeanDefinitionHolder registerPostProcessor(BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);registry.registerBeanDefinition(beanName, definition);return new BeanDefinitionHolder(definition, beanName);}這方法為BeanDefinition設(shè)置了一個(gè)Role,ROLE_INFRASTRUCTURE代表這是spring內(nèi)部的,并非用戶定義的,然后又調(diào)用了registerBeanDefinition方法,再點(diǎn)進(jìn)去,Oh No,你會(huì)發(fā)現(xiàn)它是一個(gè)接口,沒(méi)辦法直接點(diǎn)進(jìn)去了,首先要知道registry實(shí)現(xiàn)類是什么,那么它的實(shí)現(xiàn)是什么呢?答案是DefaultListableBeanFactory:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {this.beanFactory.registerBeanDefinition(beanName, beanDefinition);}這又是一個(gè)門面方法,再點(diǎn)進(jìn)去,核心在于下面兩行代碼:
//beanDefinitionMap是Map<String, BeanDefinition>, //這里就是把beanName作為key,ScopedProxyMode作為value,推到map里面 this.beanDefinitionMap.put(beanName, beanDefinition);//beanDefinitionNames就是一個(gè)List<String>,這里就是把beanName放到List中去 this.beanDefinitionNames.add(beanName);從這里可以看出DefaultListableBeanFactory就是我們所說(shuō)的容器了,里面放著beanDefinitionMap,beanDefinitionNames,beanDefinitionMap是一個(gè)hashMap,beanName作為Key,beanDefinition作為Value,beanDefinitionNames是一個(gè)集合,里面存放了beanName。打個(gè)斷點(diǎn),第一次運(yùn)行到這里,監(jiān)視這兩個(gè)變量:
DefaultListableBeanFactory中的beanDefinitionMap,beanDefinitionNames也是相當(dāng)重要的,以后會(huì)經(jīng)常看到它,最好看到它,第一時(shí)間就可以反應(yīng)出它里面放了什么數(shù)據(jù)
這里僅僅是注冊(cè),可以簡(jiǎn)單的理解為把一些原料放入工廠,工廠還沒(méi)有真正的去生產(chǎn)。
上面已經(jīng)介紹過(guò),這里會(huì)一連串注冊(cè)好幾個(gè)Bean,在這其中最重要的一個(gè)Bean(沒(méi)有之一)就是BeanDefinitionRegistryPostProcessor Bean。
ConfigurationClassPostProcessor實(shí)現(xiàn)BeanDefinitionRegistryPostProcessor接口,BeanDefinitionRegistryPostProcessor接口又?jǐn)U展了BeanFactoryPostProcessor接口,BeanFactoryPostProcessor是Spring的擴(kuò)展點(diǎn)之一,ConfigurationClassPostProcessor是Spring極為重要的一個(gè)類,必須牢牢的記住上面所說(shuō)的這個(gè)類和它的繼承關(guān)系。
除了注冊(cè)了ConfigurationClassPostProcessor,還注冊(cè)了其他Bean,其他Bean也都實(shí)現(xiàn)了其他接口,比如BeanPostProcessor等。
BeanPostProcessor接口也是Spring的擴(kuò)展點(diǎn)之一。
至此,實(shí)例化AnnotatedBeanDefinitionReader reader分析完畢。
由于常規(guī)使用方式是不會(huì)用到AnnotationConfigApplicationContext里面的scanner的,所以這里就不看scanner是如何被實(shí)例化的了。
把目光回到最開(kāi)始,再分析第二行代碼:
register(annotatedClasses);這里傳進(jìn)去的是一個(gè)數(shù)組,最終會(huì)循環(huán)調(diào)用如下方法:
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {//AnnotatedGenericBeanDefinition可以理解為一種數(shù)據(jù)結(jié)構(gòu),是用來(lái)描述Bean的,這里的作用就是把傳入的標(biāo)記了注解的類//轉(zhuǎn)為AnnotatedGenericBeanDefinition數(shù)據(jù)結(jié)構(gòu),里面有一個(gè)getMetadata方法,可以拿到類上的注解AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);//判斷是否需要跳過(guò)注解,spring中有一個(gè)@Condition注解,當(dāng)不滿足條件,這個(gè)bean就不會(huì)被解析if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {return;}abd.setInstanceSupplier(instanceSupplier);//解析bean的作用域,如果沒(méi)有設(shè)置的話,默認(rèn)為單例ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);abd.setScope(scopeMetadata.getScopeName());//獲得beanNameString beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));//解析通用注解,填充到AnnotatedGenericBeanDefinition,解析的注解為L(zhǎng)azy,Primary,DependsOn,Role,DescriptionAnnotationConfigUtils.processCommonDefinitionAnnotations(abd);//限定符處理,不是特指@Qualifier注解,也有可能是Primary,或者是Lazy,或者是其他(理論上是任何注解,這里沒(méi)有判斷注解的有效性),如果我們?cè)谕饷?#xff0c;以類似這種//AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);常規(guī)方式去初始化spring,//qualifiers永遠(yuǎn)都是空的,包括上面的name和instanceSupplier都是同樣的道理//但是spring提供了其他方式去注冊(cè)bean,就可能會(huì)傳入了if (qualifiers != null) {//可以傳入qualifier數(shù)組,所以需要循環(huán)處理for (Class<? extends Annotation> qualifier : qualifiers) {//Primary注解優(yōu)先if (Primary.class == qualifier) {abd.setPrimary(true);}//Lazy注解else if (Lazy.class == qualifier) {abd.setLazyInit(true);}//其他,AnnotatedGenericBeanDefinition有個(gè)Map<String,AutowireCandidateQualifier>屬性,直接push進(jìn)去else {abd.addQualifier(new AutowireCandidateQualifier(qualifier));}}}for (BeanDefinitionCustomizer customizer : definitionCustomizers) {customizer.customize(abd);}//這個(gè)方法用處不大,就是把AnnotatedGenericBeanDefinition數(shù)據(jù)結(jié)構(gòu)和beanName封裝到一個(gè)對(duì)象中BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);//注冊(cè),最終會(huì)調(diào)用DefaultListableBeanFactory中的registerBeanDefinition方法去注冊(cè),//DefaultListableBeanFactory維護(hù)著一系列信息,比如beanDefinitionNames,beanDefinitionMap//beanDefinitionNames是一個(gè)List<String>,用來(lái)保存beanName//beanDefinitionMap是一個(gè)Map,用來(lái)保存beanName和beanDefinitionBeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);}在這里又要說(shuō)明下,以常規(guī)方式去注冊(cè)配置類,此方法中除了第一個(gè)參數(shù),其他參數(shù)都是默認(rèn)值。
通過(guò)AnnotatedGenericBeanDefinition的構(gòu)造方法,獲得配置類的BeanDefinition,這里是不是似曾相似,在注冊(cè)ConfigurationClassPostProcessor類的時(shí)候,也是通過(guò)構(gòu)造方法去獲得BeanDefinition的,只不過(guò)當(dāng)時(shí)是通過(guò)RootBeanDefinition去獲得,現(xiàn)在是通過(guò)AnnotatedGenericBeanDefinition去獲得。
判斷需不需要跳過(guò)注冊(cè),Spring中有一個(gè)@Condition注解,如果不滿足條件,就會(huì)跳過(guò)這個(gè)類的注冊(cè)。
然后是解析作用域,如果沒(méi)有設(shè)置的話,默認(rèn)為單例。
獲得BeanName。
解析通用注解,填充到AnnotatedGenericBeanDefinition,解析的注解為L(zhǎng)azy,Primary,DependsOn,Role,Description。
限定符處理,不是特指@Qualifier注解,也有可能是Primary,或者是Lazy,或者是其他(理論上是任何注解,這里沒(méi)有判斷注解的有效性)。
把AnnotatedGenericBeanDefinition數(shù)據(jù)結(jié)構(gòu)和beanName封裝到一個(gè)對(duì)象中(這個(gè)不是很重要,可以簡(jiǎn)單的理解為方便傳參)。
這個(gè)registerBeanDefinition是不是又有一種似曾相似的感覺(jué),沒(méi)錯(cuò),在上面注冊(cè)Spring內(nèi)置的Bean的時(shí)候,已經(jīng)解析過(guò)這個(gè)方法了,這里就不重復(fù)了,此時(shí),讓我們?cè)儆^察下beanDefinitionMap beanDefinitionNames兩個(gè)變量,除了Spring內(nèi)置的Bean,還有我們傳進(jìn)來(lái)的Bean,這里的Bean當(dāng)然就是我們的配置類了:
到這里注冊(cè)配置類也分析完畢了。
大家可以看到其實(shí)到這里,Spring還沒(méi)有進(jìn)行掃描,只是實(shí)例化了一個(gè)工廠,注冊(cè)了一些內(nèi)置的Bean和我們傳進(jìn)去的配置類,真正的大頭是在第三行代碼:
refresh();不過(guò),這就是下一章的內(nèi)容了。
轉(zhuǎn)載于:https://www.cnblogs.com/CodeBear/p/10336704.html
總結(jié)
以上是生活随笔為你收集整理的剑指Spring源码(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SpringBoot注册Servlet、
- 下一篇: Codeforces Round #53