ConfigurationClassPostProcessor
解析配置类中有两类集合,一类是配置类、另一类是所有已解析的bd
- 从已有bd中过滤配置类
candidateNames:保存已被解析出来的所有待解析的bd名
configCandidates:candidateNames经过过滤的所有待解析的配置类bd
过滤条件:
检查BeanDefinition并设置 CONFIGURATION_CLASS_ATTRIBUTE
为 full
或者 lite
Full
: 即类被 @Configuration 注解修饰 && proxyBeanMethods属性为true (默认为 true)
Lite
: 被 @Component、@ComponentScan、@Import、@ImportResource 修饰的类 或者 类中有被 @Bean修饰的方法
-
configCandidates.sort()
-
解析配置类
candidates:configCandidates,待解析配置类
alreadyParsed:
do:
parse():解析,生成bd元数据(configClasses)
processConfigurationClass:
1.@Conditional条件过滤(PARSE_CONFIGURATION阶段)-> shouldSkip
2.递归解析配置类
SourceClass sourceClass = asSourceClass(configClass, filter);
do:
sourceClass = doProcessConfigurationClass()
while (sourceClass != null);
3.configurationClasses.put(configClasse)
this.deferredImportSelectorHandler.process()
:
DeferredImportSelectorGroupingHandler#register(DeferredImportSelectorHolder)
DeferredImportSelectorGroupingHandler#rprocessGroupImports
validate():校验配置类的访问权限...
configClasses:本次循环解析出来的配置类(其中可能包含已经被解析过的)
configClasses.removeAll(alreadyParsed)
loadBeanDefinitions():加载元数据为bd(configClasses)
alreadyParsed.addAll(configClasses)
candidates.clear()
newCandidateNames:所有已解析的bd名
oldCandidateNames:candidateNames
遍历newCandidateNames:
过滤掉oldCandidateNames(剩下本次解析出来bd)
如果是配置类且没有被解析过,则加入candidates中
candidateNames = newCandidateNames
while (!candidates.isEmpty())
doProcessConfigurationClass
-
处理 @Component 注解
如果类被 @Component 修饰,则处理内部类:
processMemberClasses:寻找并遍历内部类中的配置类,递归解析
-
处理 @PropertySource 注解
解析注解属性,根据注解属性中的locations,加载配置并添加到environment中
-
处理 @ComponentScan注解
根据注解属性扫描指定的包,便遍历bd中的配置类,递归解析
-
处理 @Import 注解
processImports(); 该方法处理的包括 @Import、ImportSelector、 ImportBeanDefinitionRegistrar。这三个注解或接口都可以完成Bean的引入功能。
-
ImportSelector:分为延迟加载(DeferredImportSelector)和非延迟加载
-
非延迟加载会通过selectImports()方法,获取导入的类,并遍历导入的类递归的processImports进行解析
-
延迟加载会调用
DeferredImportSelectorHandler.handle()
:deferredImportSelectors.add(new DeferredImportSelectorHolder(configClass, importSelector))
-
-
ImportBeanDefinitionRegistrar:并不立即进行解析,而是保存到 configClass 相应的属性中
-
@Import:可以通过 @Import(XXX.class) 的方式,将XXX作为configClass进行递归的解析
-
-
处理 @ImportResource 注解
解析注解属性,保存到 configClass 相应的属性中
-
处理 @Bean修饰的方法
解析注解属性,保存到 configClass 相应的属性中
-
处理其他默认接口方法
检测 配置类实现的接口中的默认方法是否被@Bean修饰,如果被修饰则也需要保存到 configClass 中
-
处理父类,如果存在,递归解析
loadBeanDefinitions
- shouldSkip?
- 处理被引入的(被 @Import 或者其他配置类内部引入)的情况
- 处理BeanMethod
- 处理ImportResource
- 处理ImportBeanDefinitionRegistrar:执行loadBeanDefinitionsFromRegistrars()方法进行导入
shouldSkip(metadata, phase)
如果phase为null,则先判断是不是配置类,如果是则走PARSE_CONFIGURATION逻辑,否则走REGISTER_BEAN逻辑
-
获取
@Conditional
上所有Condition
: -
对
Condition
集合排序 -
如果
Condition
是ConfigurationCondition
,需要condition.getConfigurationPhase()
来获取该Condition
生效的阶段 -
如果生效阶段为null或生效阶段与phase匹配,则返回
!condition.matches
:即条件不匹配的话,应该跳过matches(context, metadata)中,context包含BeanDefinitionRegistry,metadata为引入条件注解的注解元信息
deferredImportSelectorHandler.process()
:
DeferredImportSelector类结构图
-
DeferredImportSelectorGroupingHandler#register(DeferredImportSelectorHolder)
- group = getImportGroup:获取DeferredImportSelector的Group,AutoConfigurationImportSelector对应的Group是AutoConfigurationGroup
- group -> new DeferredImportSelectorGrouping(createGroup(group)) 放入
groupings
- 将DeferredImportSelectorHolder填充到上边new的对象里
configurationClasses
.put
-
DeferredImportSelectorGroupingHandler#rprocessGroupImports
遍历groupings(DeferredImportSelectorGrouping):
-> grouping.getImports():
对deferredImports中每个DeferredImportSelectorHolder:使用绑定的group进行:
group.process(holder.getMetadata(),holder.getImportSelector())
:
主要作用就是getAutoConfigurationEntry,获取spring。factories文件中自动配置类并保存到 entries中
最后返回group.selectImports()
,主要会通过配置文件中的条件进行过滤,这里返回的是Entry条目集合,最终每个条目结构为:
对每个条目调用processImports
进行处理,一般配置类只是个普通配置类,就会走processConfigurationClass
这个方法进行处理