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定义中了



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