代码改变世界

ConfigurationClassPostProcessor解读

2024-01-14 16:02  Spiderman25  阅读(5)  评论(0)    收藏  举报

首先说重点,这个类发生在调用BeanFactoryPostProcessors时,作用就是从spring容器中找中所有的bean定义,如果bean定义带上compomentScan这个注解,则把这个注解配置的包下的spring类加载到容器的bean定义中。

调用栈如下:

registerBeanDefinition:988, DefaultListableBeanFactory (org.springframework.beans.factory.support)
registerBeanDefinition:164, BeanDefinitionReaderUtils (org.springframework.beans.factory.support)
registerBeanDefinition:320, ClassPathBeanDefinitionScanner (org.springframework.context.annotation)
doScan:292, ClassPathBeanDefinitionScanner (org.springframework.context.annotation)
parse:128, ComponentScanAnnotationParser (org.springframework.context.annotation)
doProcessConfigurationClass:296, ConfigurationClassParser (org.springframework.context.annotation)
processConfigurationClass:250, ConfigurationClassParser (org.springframework.context.annotation)
parse:207, ConfigurationClassParser (org.springframework.context.annotation)
parse:175, ConfigurationClassParser (org.springframework.context.annotation)
processConfigBeanDefinitions:331, ConfigurationClassPostProcessor (org.springframework.context.annotation)
postProcessBeanDefinitionRegistry:247, ConfigurationClassPostProcessor (org.springframework.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:311, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:112, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:746, AbstractApplicationContext (org.springframework.context.support)
refresh:564, AbstractApplicationContext (org.springframework.context.support)
<init>:93, AnnotationConfigApplicationContext (org.springframework.context.annotation)
main:10, MyTest (com.csp.my)

 

 先遍历所有的bean定义,如果定义中有org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass属性,说明已经被处理过,则否再继续判断,如果bean定义是AnnotatedBeanDefinition类型的,那么就直接从bean定义中取出元数据,再从元数据metadata中取出Configuration数据,如果Configuration数据不为空或者里面有Component、ComponentScan、Import、ImportResource这些数据中的一个或者多个,那么就往定义中添加org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass属性,说明已经被处理了,同时把这个bean定义认为是可以这个处理器处理的配置。

 

 如果类被Configuration、Component、ComponentScan、Import、ImportResource标记或者类中有Bean标记的方法则符合解释的定义

 

 

 

 

 

 如果没有可以处理的配置则跳出方法。

对所有的配置进行排序处理。排序大小存在bean定义的Attribute中。

随后对符合的bean定义进行解析

 

 

 

 

 先看完整的doProcessConfigurationClass方法

 

 

 从bean定义中获取到元数据,开始对元数据进行解释。


----------
1、如果bean定义被Component标记,这里面会处理类中的内部类,如果内部类被Configuration、Component、ComponentScan、Import、ImportResource标记或者类中有Bean标记的方法,则对内部类进行处理。处理逻辑就是上次的逻辑(调这个方法processConfigurationClass),最终添加到bean定义中。

 处理内部类,如果内部类被标记(方法已在前面讲过)就对里面的内部类进行解析

 这种生成的configClass就认为是导入的

 

 

 

回到前面,接着解析被PropertySource标记的配置

 

 2、如果bean定义被PropertySources、PropertySource标记

 

那么就获取注解的value,根据这个值生成一个ResourcePropertySource,然后添加到environment的PropertySources中。是添加到最后的位置。

 

 

 

 

 

3、如果bean定义被ComponentScans、ComponentScan标记

 

 this.componentScanParser.parse方法中有如下代码

 

 可见已注册到bean定义中

 

这里是下面的parse(bdCand.getBeanClassName(), holder.getBeanName());

 

 

 

获取所有的scan属性,由于可能被标记多次,所以是一个集合,遍历所有的scan,对每个scan的包路径进行解析,如果类被Component标记,则生成bean定义,并添加到容器中。

 

随后对注册的bean定义重新进行解析,因为如果新增的bean定义有被其他注解标记的话会导致新一轮解析(调这个方法processConfigurationClass)。

 

 

 

3.5处理被 @Import标记的类,

 

 

 

 

 

 这种生成的configClass就认为是导入的

 

 如果是ImportSelector类型并且是DeferredImportSelector类型时,把DeferredImportSelector放到处理器的列表中,后面会进行统一的处理。

 

 

 

 收集好所有的导出来的类后,再对每个类过行判断

如果是ImportSelector类型的,进行自动导入操作,如果springboot的自己导入功能。

如果是ImportBeanDefinitionRegistrar类型的,则封装成ImportBeanDefinitionRegistrar放到configClass的importBeanDefinitionRegistrars。在外层方法会处理。

否则添加到容器的bean定义中。



4、如果bean定义被ImportResource标记,则添加到ConfigurationClass的importedResources中,随后对importedResources进行解析导入bean定义,例如你可以导入xml形式的配置文件

 

 

 

 5处理bean定义类中被@Bean标记的方法,把每个bean方法封装成MethodMetadata然后添加到该类配置ConfigurationClass的beanMethods中。这个应该在后面会被调用并添加到容器中。哈哈

 

 6、类的接口中的默认方法如果被@Bean标记,则也添加到ConfigurationClass的beanMethods中

 

 7如果这个类还有父类,则返回父类,然后外面的方法会继续解析。

 

方法出来后,会调用这个方法,这个是处理DeferredImportSelector自动导入功能的。

 开始处理上面的DeferredImportSelectorHolder列表,handle方法在之前已经被调用过多次,所以已经有列表了,现在开始process处理这些列表。

redister,首先把deferredImports的元素所有元素注册到groupings中,key为组名,value为DeferredImportSelectorGrouping类型,而且这个类型可以持有多个selectorHolder。

processGroupImports,遍历groupings,对元素中DeferredImportSelectorGrouping的getImports再遍历,getImports实际就是调用所有selector的selectImports方法生成Entry列表。

 

 

 

 

回到前面代码

 

 

------------------------------------------------------------------

结束

 -----------------------------------------------------------------

 

后面会

导进来的configClass会添加到bean定义中。如用@Import导出来的

从configClass里面的@bean方法定义加载bean定义

从导入资源加载bean定义,把configClass导入到bean定义中。如加载xml的外部bean

把configClass中的getImportBeanDefinitionRegistrars注册到bean定义中,如果bean是ImportBeanDefinitionRegistrar类型的,前面会被configClass中的getImportBeanDefinitionRegistrars。

注这里的configClasses就是所有上面解析到的类,包括扫描出的以及手动添加到的。

 

 

 通过内部类方式导进来、Import导进来这里就会为true,而对于componentScan注解,在前面处理的时候已经加到bean定义中了

 

 

最后从容器中找出还没有被处理过的定义(由于解析而新增的)再一次处理。