• Spring ConfigurationClassPostProcessor Bean解析及自注册过程


    一、Bean的自注册过程

      

    二、自注册过程说明

    ConfigurationClassParser解析流程

       1、处理@PropertySources注解,配置信息的解析

      2、处理@ComponentScan注解:使用ComponentScanAnnotationParser扫描basePackage下的需要解析的类(@SpringBootApplication注解也包括了@ComponentScan注解,只不过basePackages是空的,空的话会去获取当前@Configuration修饰的类所在的包[这个会在下面详细解释]),并注册到BeanFactory中(这个时候bean并没有进行实例化,而是进行了注册。具体的实例化在finishBeanFactoryInitialization方法中执行)。对于扫描出来的类,递归解析

      3、处理@Import注解:先递归找出所有的注解,然后再过滤出只有@Import注解的类,得到@Import注解的值。比如查找@SpringBootApplication注解的@Import注解数据的话,首先发现@SpringBootApplication不是一个@Import注解,然后递归调用修饰了@SpringBootApplication的注解,发现有个@EnableAutoConfiguration注解,再次递归发现被@Import(EnableAutoConfigurationImportSelector.class)修饰,还有@AutoConfigurationPackage注解修饰,再次递归@AutoConfigurationPackage注解,发现被@Import(AutoConfigurationPackages.Registrar.class)注解修饰,所以@SpringBootApplication注解对应的@Import注解有2个,分别是@Import(AutoConfigurationPackages.Registrar.class)和@Import(EnableAutoConfigurationImportSelector.class)。找出所有的@Import注解之后,开始处理逻辑:

         (1)、遍历这些@Import注解内部的属性类集合

         (2)、如果这个类是个ImportSelector接口的实现类,实例化这个ImportSelector,如果这个类也是DeferredImportSelector接口的实现类,那么加入ConfigurationClassParser的deferredImportSelectors属性中让第6步处理。否则调用ImportSelector的selectImports方法得到需要Import的类,然后对这些类递归做@Import注解的处理

         (3)、如果这个类是ImportBeanDefinitionRegistrar接口的实现类,设置到配置类ConfigurationClass的importBeanDefinitionRegistrars属性中

         (4)、其它情况下把这个类入队到ConfigurationClassParser的importStack(队列)属性中,然后把这个类当成是@Configuration注解修饰的类递归重头开始解析这个类

      4、处理@ImportResource注解:获取@ImportResource注解的locations属性,得到资源文件的地址信息。然后遍历这些资源文件并把它们添加到配置类的importedResources属性中

      5、处理@Bean注解:获取被@Bean注解修饰的方法,然后添加到配置类的beanMethods属性中

      6、处理DeferredImportSelector:处理第3步@Import注解产生的DeferredImportSelector,进行selectImports方法的调用找出需要import的类,然后再调用第3步相同的处理逻辑处理

    @SpringBootApplication注解

      @SpringBootApplication注解被@EnableAutoConfiguration修饰,@EnableAutoConfiguration注解被@Import(EnableAutoConfigurationImportSelector.class)修饰,所以在第3步会找出这个@Import修饰的类EnableAutoConfigurationImportSelector,这个类刚好实现了DeferredImportSelector接口,接着就会在第6步被执行。第6步selectImport得到的类就是自动化配置类。

      EnableAutoConfigurationImportSelector的selectImport方法会在spring.factories文件中找出key为EnableAutoConfiguration对应的值【这些值就是所谓的自动化配置类(XXXAutoConfiguration)】。

      ConfigurationClassParser解析完成之后,被解析出来的类会放到configurationClasses属性中。然后使用ConfigurationClassBeanDefinitionReader去解析这些类。

    ComponentScanAnnotationParser包扫描相关

      首先启动一个springboot web工程,找到ApplicationContext的父类org.springframework.context.support.AbstractApplicationContext

      

      我们发现,其真实的对象的类型是AnnotationConfigEmbeddedWebApplicationContext。 自身构造过程如下。

      

      继续追踪AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)

      

      

      终于找到了ConfigurationClassPostProcessor自注册后置处理器。这里有个有趣的ConfigurationClassPostProcessor解析流程, 内部调用中会使用 ComponentScanAnnotationParser去扫描,ComponentScanAnnotationParser类的parse方法有这样一段逻辑

    if (basePackages.isEmpty()) {
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }

      参考下面的相关图:

      也就是如果basePackages没有配置,会找declaringClass 对应包及其子包,declaringClass对应springboot项目中我们写的Application.java(@SpringBootApplication)

      

      

      

      

    调用栈

       

    实际项目结构

      

      包结构这样的话,即使不配置componentScan,不使用AutoConfiguration,也可以扫描到bean。Application.java带有@SpringbootApplication注解,该注解中带有@ComponentScan注解,Application.java包的范围包含了所有java文件,所以项目中所有bean都可以被扫描到。

      注:declaringClass 指的是带有@ComponentScan 注解的类

       欢迎访问微信订阅号原文:ConfigurationClassPostProcessor Bean解析及自注册过程

      就先分享这么多了,更多分享请关注我们的技术公众吧!!!

  • 相关阅读:
    02-JavaScript语法
    001 docker基本环境的搭建
    023 虚拟机的安装
    022 虚拟机的网络配置
    021 虚拟机的安装
    004 java客户端的开发
    003 Rabbitmq中交换机的类型
    002 Rabbitmq的基础概念
    001 基础环境的搭建
    001 基本的环境的安装
  • 原文地址:https://www.cnblogs.com/hujunzheng/p/9711440.html
Copyright © 2020-2023  润新知