栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Spring源码】9. 重要的ConfigurationClassPostProcessor

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Spring源码】9. 重要的ConfigurationClassPostProcessor

之前的文章捋了捋PostProcessor的处理流程,其中有一个特别重要的PostProcessor:ConfigurationClassPostProcessor,即配置类的后置处理器(参与BeanFactory的建造)

主要功能:

  1. 解析被 @Configuration修饰的配置类
  2. 解析 @ComponentScan扫描的包
  3. 解析 @ComponentScans扫描的包
  4. 解析被 @Import注解修饰的类
入口在哪里

上一篇我们捋了捋invokeBeanFactoryPostProcessors()的整体逻辑,由于ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor所以他会在invokeBeanFactoryPostProcessors()方法中被处理,我们debug到invokeBeanFactoryPostProcessors()方法中

ConfigurationClassPostProcessor是在第二步(处理子类,详见上一篇文章)中,即处理实现了BeanDefinitionRegistryPostProcessor接口的步骤中被处理的,而且发现有一点就是我刚开始使用配置文件进行配置的时候,整个debuginvokeBeanFactoryPostProcessors()方法的过程中都没有看到ConfigurationClassPostProcessor这个类,当我使用配置类时,才在上图的位置发现了ConfigurationClassPostProcessor

继续执行,进入对子类单独处理的遍历中

在这里会进入到ConfigurationClassPostProcessor中实现的postProcessBeanDefinitionRegistry ( BeanDefinitionRegistry registry ) 方法

这里会先生成一个registryId,用做容器中Bean的唯一标识,然后判断这个传入的registry是否已经被处理过,处理过,抛出异常,未被处理过,则将其registryId添加进已经处理的集合对象中,之后就会进入核心处理环节,如下图

processConfigBeanDefinitions() 筛选Bean

进入该方法后,先创建了一个用于存放BeanDefinitionHolder的对象集合List configCandidates,获取当前传入的registry(此处为DefaultListableBeanFactory)中所有已经注册的BeanDefinition的beanName,紧接着遍历这些BeanDefinition的beanName,筛选出被特定注解修饰的bean

上图中的遍历筛选部分的代码

for ( String beanName : candidateNames ) {
 
BeanDefinition beanDef = registry.getBeanDefinition ( beanName ) ;
if ( beanDef.getAttribute ( ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null ) {
if ( logger.isDebugEnabled ()) {
logger.debug ( "Bean definition has already been processed as a configuration class: " + beanDef ) ;
      }
}
else if ( ConfigurationClassUtils.checkConfigurationClassCandidate( beanDef, this.metadataReaderFactory ));
configCandidates.add ( new BeanDefinitionHolder ( beanDef, beanName )) ;
   }
} 
复制代码

上面的for循环,依次获取BeanDefinition,并进行两个判断:

1. 是否包含属性ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE)

2. 判断当前BeanDefinition是否是一个配置类,并根据注解类型为BeanDefinition设置属性(以便后续进行调用),这个主要逻辑在checkConfigurationClassCandidate()方法中,后面会单出一篇文章详细介绍这个函数,它里面的主要逻辑是:

  1. 设置为full/lite

    1. 如果被@Configuration修饰则为full
    2. 如果被@Bean、@Component、@ComponentScan、@Import、@ImportResoure修饰则属性值设为lite
  2. 如果配置类上被order修饰,则为BeanDefinition添加order参数

遍历判断后,如果未发现有配置相关的类,则直接返回

对添加@Order注解的类,进行排序操作

继续判断当前类型是否是SingletonBeanRegistry类型(进行BeanName生成器的配置)

解析配置类

之后就到了重要的一步:解析配置类

先实例化ConfigurationClassParser类+初始化相关参数(如下图中注释)

之后进入配置类的解析工作parser.parse()

此处会解析带有@ComponentScan、@ComponentScans、@Import、@ImportResource、@Bean、@Controller的BeanDefinition 但有一点需要注意,这里只是把两种类(添加了@Configuration注解的类和通过ComponentScan注解扫描的类)加入到BeanDefinitionMap中,其余的方式(@Import注册的类、@Bean方法定义的类)在parse()这一步不会被解析为BeanDefinition放进BeanDefinitionMap中(实际在this.reader.loadBeanDefinitions()中实现,只是发现流程是这样,欢迎知道原因的同学踢踢我(。ì _ í。)抱拳多谢.gif)

之后就进入了递归调用processConfigurationClass()方法来处理配置类的内部类所带注解、内部类的内部类所带注解(如果有的话)……

呃。太长叻(˶‾᷄ ⁻̫ ‾᷅˵)

下篇我们继续详细看下递归调用的processConfigurationClass()方法(。・ω・。)ノ

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1031187.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号