javascript
Spring源码(1)
準(zhǔn)備spring環(huán)境:
@org.junit.Test public void test01(){//把spring所有環(huán)境準(zhǔn)備好// 1.準(zhǔn)備好DefaultListableBeanFactory// 實例化一個bdReader和一個ScannerAnnotationConfigApplicationContext applicationContext =new AnnotationConfigApplicationContext();//把一個class轉(zhuǎn)成bd,最后put到mapapplicationContext.register(AppConfig.class);//初始化spring的環(huán)境applicationContext.refresh();}構(gòu)造方法
進(jìn)入AnnotationConfigApplicationContext類:
1.調(diào)用AnnotationConfigApplicationContext()構(gòu)造方法的時候,會先調(diào)用父類構(gòu)造器new出一個工廠DefaultListableBeanFactory。
//new一個工廠DefaultListableBeanFactory public GenericApplicationContext() {this.beanFactory = new DefaultListableBeanFactory(); }2.初始化一個bean的讀取器AnnotatedBeanDefinitionReader和一個掃描器ClassPathBeanDefinitionScanner。
?reader可以讀取被加了注解的類,scanner可以掃描所有加了注解的bean。
public AnnotationConfigApplicationContext() {/*** 父類的構(gòu)造方法* 創(chuàng)建一個讀取注解的BeanDefinition讀取器* 什么是bean定義?BeanDefinition*///reader能夠讀取被加了注解的類 this是一個注冊器,用來將BeanDefinition轉(zhuǎn)為工廠中的mapthis.reader = new AnnotatedBeanDefinitionReader(this);//可以用來掃描包或者類,繼而轉(zhuǎn)換成bd//但是實際上我們掃描包工作不是scanner這個對象來完成的//是spring自己new的一個ClassPathBeanDefinitionScanner//這里的scanner僅僅是為了程序員能夠在外部調(diào)用AnnotationConfigApplicationContext對象的scan方法this.scanner = new ClassPathBeanDefinitionScanner(this); }3.進(jìn)入this.reader = new AnnotatedBeanDefinitionReader(this)方法,一直到:?
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source)?3.1? 該方法中首先調(diào)用了unwrapDefaultListableBeanFactory()方法,這樣獲取到工廠。當(dāng)前的工廠是一個空的工廠,給工廠設(shè)置依賴比較器(應(yīng)該是這樣翻譯的吧),設(shè)置處理延遲加載的功能。
?????? 3.2? 設(shè)置BeanDefinitionHolder(裝的是beanName+BeanDefinition,基本沒啥作用,只是為了傳參方便,本來傳beanName和BeanDefinition,現(xiàn)在傳BeanDefinitionHolder就可以)。org.springframework.context.annotation.internalConfigurationAnnotationProcessor
?????? 3.3? 將ConfigurationClassPostProcessor,AutowiredAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,EventListenerMethodProcessor?,DefaultEventListenerFactory 6個
spring的內(nèi)置的類轉(zhuǎn)為6個RootBeanDefinition,然后注冊器BeanDefinitionRegistry將這些個類注冊進(jìn)工廠,最后這個RootBeanDefinition轉(zhuǎn)換成beanName+BeanDefinition的方式放入BeanDefinitionHolder。
該registerAnnotationConfigProcessors方法的目的就是將ConfigurationClassPostProcessor類以及其他內(nèi)置類裝入BeanDefinitionHolder,然后返回BeanDefinitionHolder。
接下來回到2。然后是研究this.scanner = new ClassPathBeanDefinitionScanner(this)。這個scanner的作用基本很小,如果在外部比如調(diào)用applicationContext.scan("")方法才會利用到。否則一切的掃描注冊和它沒有啥關(guān)系。
這樣,AnnotationConfigApplicationContext()構(gòu)造完成。
注冊
接下來就是注冊。進(jìn)入applicationContext.register(AppConfig.class)方法。
4.進(jìn)入doRegisterBean()方法:
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {/*** 根據(jù)指定的bean創(chuàng)建一個AnnotatedGenericBeanDefinition* 這個AnnotatedGenericBeanDefinition可以理解為一個數(shù)據(jù)結(jié)構(gòu)* AnnotatedGenericBeanDefinition包含了類的其他信息,比如一些元信息* scope,lazy等等*/AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);/*** 判斷這個類是否需要跳過解析* 通過代碼可以知道spring判斷是否跳過解析,主要判斷類有沒有加注解*/if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {return;}//不知道abd.setInstanceSupplier(instanceSupplier);/*** 得到類的作用域*/ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);/*** 把類的作用域添加到數(shù)據(jù)結(jié)構(gòu)結(jié)構(gòu)中*/abd.setScope(scopeMetadata.getScopeName());/*** 生成類的名字通過beanNameGenerator*/String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));/*** 處理類當(dāng)中的通用注解* 分析源碼可以知道他主要處理* Lazy DependsOn Primary Role等等注解* 處理完成之后processCommonDefinitionAnnotations中依然是把他添加到數(shù)據(jù)結(jié)構(gòu)當(dāng)中**/AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);//這里qualifiers傳過來是null/*** 如果在向容器注冊注解Bean定義時,使用了額外的限定符注解則解析* 關(guān)于Qualifier和Primary前面的課當(dāng)中講過,主要涉及到spring的自動裝配* 這里需要注意的* byName和qualifiers這個變量是Annotation類型的數(shù)組,里面存不僅僅是Qualifier注解* 理論上里面里面存的是一切注解,所以可以看到下面的代碼spring去循環(huán)了這個數(shù)組* 然后依次判斷了注解當(dāng)中是否包含了Primary,是否包含了Lazyd*/if (qualifiers != null) {for (Class<? extends Annotation> qualifier : qualifiers) {如果配置了@Primary注解,如果加了則作為首選if (Primary.class == qualifier) {abd.setPrimary(true);}//懶加載,前面加過else if (Lazy.class == qualifier) {abd.setLazyInit(true);}else {//如果使用了除@Primary和@Lazy以外的其他注解,則為該Bean添加一個根據(jù)名字自動裝配的限定符//這里難以理解,后面會詳細(xì)介紹abd.addQualifier(new AutowireCandidateQualifier(qualifier));}}}for (BeanDefinitionCustomizer customizer : definitionCustomizers) {customizer.customize(abd);}/*** 這個BeanDefinitionHolder也是一個數(shù)據(jù)結(jié)構(gòu)*/BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);/*** ScopedProxyMode需要結(jié)合web去理解* */definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);/*** 把上述的這個數(shù)據(jù)結(jié)構(gòu)注冊給registry* registy就是AnnotatonConfigApplicationContext* AnnotatonConfigApplicationContext在初始化的時候通過調(diào)用父類的構(gòu)造方法* 實例化了一個DefaultListableBeanFactory* *registerBeanDefinition里面就是把definitionHolder這個數(shù)據(jù)結(jié)構(gòu)包含的信息注冊到* DefaultListableBeanFactory這個工廠*/BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); }(1)先把要注冊的bean轉(zhuǎn)為AnnotatedGenericBeanDefinition(AGBD),AnnotatedGenericBeanDefinition包括了bean的其他信息,比如一些元信息,scope,lazy等。
(2)把類的作用域的名字添加到AGBD中,并且得到注冊bean的名字。processCommonDefinitionAnnotations()方法將AGBD中的信息拿出來進(jìn)行處理,主要處理一些常用的注解,處理完成放回AGBD。
(3)把AnnotatedGenericBeanDefinition裝入BeanDefinitionHolder,然后BeanDefinitionRegistry把BeanDefinitionHolder中的信息(bean)注冊進(jìn)入工廠。
初始化Spring環(huán)境
5.進(jìn)入refresh()方法。
(1)調(diào)用prepareRefresh()方法,這是刷新前的準(zhǔn)備工作。獲取容器的當(dāng)時時間,同時給容器設(shè)置同步標(biāo)識。
(2)refresh()-->obtainFreshBeanFactory()-->refreshBeanFactory()獲取工廠
(3)調(diào)用prepareBeanFactory(beanFactory):給工廠設(shè)置ClassLoader,bean表達(dá)式解釋器,添加后置處理器beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))到工廠中的一個list中,在bean實例化的時候在拿出來插手。
(4)postProcessBeanFactory(beanFactory)
(5)invokeBeanFactoryPostProcessors(beanFactory),實例化并調(diào)用所有已注冊BeanFactoryPostProcessor的bean,
必須在單例bean實例化之前調(diào)用。
??? ----->invokeBeanFactoryPostProcessors(beanFactory)
??????????? ------->invokeBeanFactoryPostProcessors(beanFactory,getBeanFactoryPostProcessors()):getBeanFactoryPostProcessors()方法獲取自己定義的,沒有@Component的后置處理器。繼續(xù)進(jìn)入invokeBeanFactoryPostProcessors(beanFactory,getBeanFactoryPostProcessors())方法:
???????????a.判斷beanFactory的類型是不是和注冊器BeanDefinitionRegistry一個類型。如果是的話,創(chuàng)建兩個list,一個是BeanFactoryPostProcessor類型,一個是BeanDefinitionRegistryPostProcessor類型。BeanDefinitionRegistryPostProcessor其實也是繼承自BeanFactoryPostProcessor,就是多擴(kuò)展了一個方法。這兩個list都是處理我們自己定義的后置處理器。
?????????? b.建立一個BeanDefinitionRegistryPostProcessor類型的list叫做currentRegistryProcessors,這個list是處理Spring自帶的后置處理器,并不是我們定義的,和a中的要有所區(qū)分。在3.3中spring已經(jīng)把自己內(nèi)部的6個后置處理器放入beanFcatory中了。現(xiàn)在根據(jù)BeanDefinitionRegistryPostProcessor取出子類放入currentRegistryProcessors。這樣的話,就可以讓子類去完成一些事,避免了高度耦合。
?????????? c.把a(bǔ)和b中類型為BeanDefinitionRegistryPostProcessor的list合并,也就是把我們定義的和spring內(nèi)置的后置處理器放在一塊。然后調(diào)用invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry)方法,進(jìn)入方法調(diào)用擴(kuò)展方法postProcessBeanDefinitionRegistry(registry)方法,也就是子類要實現(xiàn)該方法。這也是一個擴(kuò)展點。目前學(xué)到的有三個擴(kuò)展點:BeanPostProcessor,BeanPostFactoryProcessor,BeanDefinitionRegistryPostProcessor。BeanDefinitionRegistryPostProcessor繼承自BeanPostFactoryProcessor,但是又在BeanPostFactoryProcessor的基礎(chǔ)上進(jìn)行了擴(kuò)展。
???????????d.接著c講,BeanDefinitionRegistryPostProcessor的子類ConfigurationClassPostProcessor實現(xiàn)了postProcessBeanDefinitionRegistry(registry)方法,進(jìn)入方法,調(diào)用了processConfigBeanDefinitions(registry)方法。在這個方法中,取出工廠中所有的BeanDefinition,包括自定義的以及spring內(nèi)置的。從每一個BeanDefinition獲取到原始bean的元信息,判斷bean是不是加了@Configuration注解。如果是,加入到BeanDefinitionHolder的list中,如果不是,再繼續(xù)判斷是否加了@Component,@ComponentScan,@Import,@ImportResource這些注解,如果是,同樣加入到BeanDefinitionHolder的list中。接下來就是解析這些加了注解的類。調(diào)用parser.parse(candidates)方法進(jìn)行解析。parse方法中調(diào)用了另外的parse(AnnotationMetadata,beanName)方法來進(jìn)行解析。繼續(xù)調(diào)用processConfigurationClass()方法,繼續(xù)調(diào)用doProcessConfigurationClass()方法,在該方法中,處理@ComponentScan的信息。調(diào)用this.componentScanParser.parse()方法,該方法中定義了一個ClassPathBeanDefinitionScanner作為掃描器,繼續(xù)調(diào)用scanner.doScan()方法,這個方法是很重要的方法,用來掃描包。首先定義一個BeanDefinitionHolder,負(fù)責(zé)裝掃描出來的BeanDefinition。調(diào)用findCandidateComponents(basePackages)方法,掃描basePackage路徑下的java文件,符合條件的并把它轉(zhuǎn)成BeanDefinition類型。調(diào)用scanCandidateComponents(String basePackage)方法,把.class文件掃描出來。
?
總結(jié)
以上是生活随笔為你收集整理的Spring源码(1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Aware接口
- 下一篇: SpringSecurity认证流程回顾