3.1 前言
當 需要解析的 BeanDefinition集合收集完畢后梦湘,,接下來就會 遍歷 這個集合里的每一個 BeanDefinition,
解析@Component,@PropertySource盯腌,@ComponentScan, @Import陨瘩,@ImportResource腕够, @Bean级乍,等注解,將各注解的解析結(jié)果存入對應的容器,以待后續(xù)進一步處理燕少。
把元數(shù)據(jù)對象和beanName封裝成ConfigurationClass 對象卡者,繼續(xù)往下走
會先進行@Conditional注解的判斷蒿囤,如果不符合客们,就會跳過,符合就繼續(xù)往下走
3.1 解析 @Component
這個主要是為了 解析該類的內(nèi)部類 材诽,如果內(nèi)部類有 @Component / @ComponentScan / @Import / @ImportResource 注解底挫,需要去解析這個類
取出內(nèi)部類,判斷有沒有 @Component / @ComponentScan / @Import / @ImportResource
判斷的條件的話還是 和一開始過濾的時候一樣脸侥,會有一個需要解析的注解數(shù)組 來匹配
就是這四個注解
匹配到了建邓,說明這個內(nèi)部類需要解析,
把他封裝成 ConfigurationClass 對象睁枕,ConfigurationClass importBy 等于他的外部類的ConfigurationClass對象 官边,beanName是為空的
如果是別其他類帶進來的 bean類,此時的ConfigurationClass 的beanName都是為Null.
傳入 這個 ConfigurationClass 對象 外遇,遞歸調(diào)用 processConfigurationClass 去解析它注簿,流程一樣。
最后加入到ConfigurationClassParser 對象的configurationClasses map列表中跳仿, 待內(nèi)部類的解析流程走完诡渴,外部類 走完也會加入到 這個map中。
所以菲语,外部類和內(nèi)部類全部解析完妄辩, map列表是這樣的
3.2 解析 @PropertySource
@PropertySource 注解 用來 導入 配置文件,將配置文件的信息 納入到配置環(huán)境中
根據(jù)配置的 配置文件路徑山上,創(chuàng)建PropertySource對象眼耀,然后加入到Environment對象中
3.3 解析 @ComponentScan
該doProcessConfigurationClass方法繼續(xù)往下走
如果該類有 @ComponentScan 注解,同樣的也是 創(chuàng)建一個 掃描器佩憾,掃 @ComponentScan配置的包下 是否有符合的類 需要注冊畔塔,返回 BeanDefinitionHolder集合。
然后調(diào)用 ConfigurationClassUtils.checkConfigurationClassCandidate() 方法判斷 每個 beanDefinition 是否需要被解析鸯屿,和第二點開始哪里判斷的一樣:
是否有@Configuration 注解 + 是否有 @Component / @ComponentScan / @Import / @ImportResource
如果需要解析澈吨,遞歸 parse 方法,重新開始解析寄摆,
最后都加入到ConfigurationClassParser 對象的configurationClasses map列表
3.4 解析 @Import
@Import 可以導入一個類谅辣,讓他注冊到spring容器中
3.4.1 getImports(sourceClass) ,收集所有@Import 進來的類
這個方法會收集所有的@Import里面配置的類婶恼,封裝成SourceClass對象桑阶,裝進集合中
如果收集的@Import進來的類不為空柏副,就開始遍歷這些類
3.4.2 如果Import進來的是ImportSelector 接口類型
ImportSelector 接口 : selectImports 會返回一串類的 全限定名稱, 在該解析過程中,這個過程中會被調(diào)用蚣录,并導入這些類
public interface ImportSelector {
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
會先實例化這個類割择,判斷是不是 DeferredImportSelector 類型的
1. 如果是 DeferredImportSelector 類型
把他加入到ConfigurationClassParser對象的deferredImportSelectorHandler屬性的deferredImportSelectors 集合中
2. 如果只是單純的 ImportSelector 類型
調(diào)用ImportSelector接口的selectImports,返回一串類的 全限定名稱數(shù)組萎河,獲取class對象荔泳,封裝成SourceClass集合,遞歸調(diào)用 @Import的解析流程虐杯,導入他們所要導入的類
最后都加入到ConfigurationClassParser 對象的configurationClasses map列表
importBy屬性為導入他的類的ConfigurationClass對象
3.4.3 如果Import進來的是ImportBeanDefinitionRegistrar 接口類型
1. ImportBeanDefinitionRegistrar 作用
ImportBeanDefinitionRegistrar接口玛歌,如果被導入進來的類是 實現(xiàn)了這個接口,那么在該解析過程中, 會被調(diào)用到 registerBeanDefinitions 方法擎椰,會傳入 導入他的類的 元數(shù)據(jù)AnnotationMetadata對象 和 BeanDefinitionRegistry 對象支子。
public interface ImportBeanDefinitionRegistrar {
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
這個接口用處挺重要的:往往用來導入一些其他的類進來
AnnotationMetadata 對象 可以獲取導入他的類的元數(shù)據(jù),用來獲取注解的配置信息等
BeanDefinitionRegistry對象 : 用來注冊其他類
比如 mybatis的@MapperScan 注解
注解mapper接口的BeanDefinition對象到 spring容器中
2.實例化該ImportBeanDefinitionRegistrar 實例达舒,放入導入他的類的ConfigurationClass的importBeanDefinitionRegistrars集合里
3.4.4 導入的類 沒有實現(xiàn)以上接口
封裝被導入的類為ConfigurationClass對象值朋,遞歸processConfigurationClass 方法,重頭解析被導入的類 的 以上所有注解巩搏。
最后都加入到ConfigurationClassParser 對象的configurationClasses map列表中
3.5 解析@ImportResource
解析完@Import注解后昨登,開始解析@ImportResource,@ImportResource可以導入一個applicationContext的xml文件塔猾,注冊里面配置的類
3.6 解析@Bean
接下來解析@Bean
獲取所有有@Bean注解的方法
遍歷篙骡,封裝成BeanMethod對象 ConfigurationClassParser 加到ConfigClass.beanMethods容器中
至此,所有的解析工作都已完成丈甸。
3.7 解析結(jié)果與對應存放的容器小結(jié)
1.configurationClassParser的 configurationClasses
有@Component注解的類 和他需要導入類的內(nèi)部類
有 @ComponentScan 注解的類 和他掃描到的 所有類
有 @Import注解的類 和 他導進來的所有類 (除導進來的是DeferredImportSelector,ImportBeanDefinitionRegistrar 接口)
封裝成ConfigurationClass糯俗, 會放在ConfigurationClassParser的 configurationClasses屬性中
private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();
2.ConfigurationClassParser.deferredImportSelectorHandler.deferredImportSelectors
導進來的 DeferredImportSelector接口類
放在 ConfigurationClassParser對象的deferredImportSelectorHandler屬性的deferredImportSelectors 集合中
private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();
private class DeferredImportSelectorHandler {
@Nullable
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
}
3.ConfigurationClassParser.configurationClasses[n].importBeanDefinitionRegistrars
導進來的 ImportBeanDefinitionRegistrar 接口類型
放在ConfigurationClass的importBeanDefinitionRegistrars
private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars ;
4.ConfigurationClass.beanMethods
@Bean 注解的方法 封裝成 BeanMethod
放在ConfigurationClass的 beanMethods 中
private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();
4.DeferredImportSelector接口的調(diào)用
最終也是會調(diào)到我們自己被@Import進來的DeferredImportSelector實現(xiàn)類的selectImports方法里
只不過他里面要經(jīng)過 DeferredImportSelector.Group的操作,比較復雜睦擂,礙于文章篇幅得湘,這里就先略過了。