Spring解析@ComponentScan注解的执行流程

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6


文章目录

  • ​​0、总体的执行流程图​​
  • ​​1、测试入口​​
  • ​​2、AbstractApplicationContext类的refresh方法​​
  • ​​3、PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors方法​​
  • ​​4、ConfigurationClassPostProcessor类的processConfigBeanDefinitions方法​​
  • ​​5、ConfigurationClassParser类的parse方法​​
  • ​​6、ConfigurationClassParser类的processConfigurationClass方法​​
  • ​​7、最终的doProcessConfigurationClass方法​​
  • ​​8、扫描BD方法doScan​​




通过本文你将明白:Spring是在代码的什么位置解析@Configuration注解,以及解析@Configuration配置类上面的@ComponentScan注解。整个执行流程中涉及很多的解析细节,本文的讲解仅涉前面的注解内容,其他细节不做过多阐述。



0、总体的执行流程图

Spring解析@ComponentScan注解的执行流程_java


1、测试入口

配置类:

@ComponentScan("pers.mobian.springeighth")
@Configuration
public class Config {
}

测试类:

public class MainTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
}
}


2、AbstractApplicationContext类的refresh方法

调用构造方法,实例化AnnotationConfigApplicationContext类,解析配置注解的位置在refresh方法中。

点开refresh方法,会调用对应的invokeBeanFactoryPostProcessors(beanFactory)方法

Spring解析@ComponentScan注解的执行流程_实例化_02


3、PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors方法

该方法主要处理两件事情:BD:BeanDefinition

1、处理实现了BeanDefinitionRegisterPostProcess接口的类,调用对应的postProcessBeanDefinitionRegistry方法。

2、处理实现了BeanFactoryPostProcess接口的类,调用对应的postProcessBeanFactory方法。

两者的功能依次为:

1、向Spring的BD集合中添加BD,由于该接口带有注册功能,所以我们可以人为的向向容器中添加BD,(注意区分开,此处添加的是BD,Bean在refresh方法的其他方法中实现)

2、BeanFactory的后置处理器,可对比理解Bean的后置处理器(BeanPostProcess),该接口可完成一些对Bean工厂的逻辑处理

在Spring源码中,第一个含有注册功能的接口实现类为ConfigurationClassPostProcessor类(其余几个类为Spring自带的测试代码)。这个类对应的就是我们的@Configuration注解

Spring解析@ComponentScan注解的执行流程_跳出循环_03


下图为该方法的部分执行逻辑:(注意ConfigurationClassPostProcessor类,实现了PriorityOrdered接口)

1、创建一个集合用于存放即将要处理的BeanDefinitionRegistryPostProcessor

2、根据接口类型去获取类

3、校验是否实现了PriorityOrdered接口

4、将数据添加到对应的集合中

5、将集合中的内容进行排序

6、依次执行注册接口对应的方法

Spring解析@ComponentScan注解的执行流程_java_04


4、ConfigurationClassPostProcessor类的processConfigBeanDefinitions方法

在该方法中,Spring会获取我们在实例化AnnotationConfigApplicationContext类时候传入的参数,然后对类进行判断,符合条件的配置类会添加到一个list集合中。在配置类不为空的情况下,会去创建一个ConfigurationClassParser对象,用来解析我们传入的配置类。

图中主要流程为:

1、传入指定的配置类集合,进行解析(解析类上的注解,此处就包括了我们的@ComponentScan注解)

2、对相关内容进行校验

3、通常配置类中还有@Bean定义的Bean、使用@ImportResource导入xml文件中定义的Bean等。调用loadBeanDefinitions方法,就会将这些Bean,添加到BDMap中,在parse方法中也进行了扫描处理,但是那一步仅仅把它们添加到了对应的集合中,没有添加到BDMap中

Spring解析@ComponentScan注解的执行流程_java_05



补充:

此处使用了一个do while循环来处理配置类,而不是直接执行方法,为的是避免我们在解析配置类的时候,可能配置类内部定义的Bean也是一个配置类。只有当我们解析出来的配置类都被解析以后,我们才会真正的跳出循环,即对应配置类的解析操作才算完成


5、ConfigurationClassParser类的parse方法

根据我们传入配置类的不同类型,再调用对应的parse方法

Spring解析@ComponentScan注解的执行流程_流程图_06


6、ConfigurationClassParser类的processConfigurationClass方法

Spring解析@ComponentScan注解的执行流程_java_07


7、最终的doProcessConfigurationClass方法

该方法中会解析各种注解,其中就包含了我们本次博客的重点@ComponentScan注解

Spring解析@ComponentScan注解的执行流程_跳出循环_08


8、扫描BD方法doScan

上一步的parse方法,会调用ComponentScanAnnotationParser类的parse方法,然后调用scanner.doScan(StringUtils.toStringArray(basePackages))方法,完成对应的扫描操作。

在doScan方法中,主要行为为:

1、basePackages:遍历传入进来的路径数组

2、findCandidateComponents:扫描指定路径下所有符合要求的类

3、registerBeanDefinition:将符合要求的类封装成BD的形式,添加到对应的集合中

具体的如何根据路径获取符合要求的类,可以参考我之前的博客:​​获取指定路径,扫描路径下指定类(仿Spring)​​

Spring解析@ComponentScan注解的执行流程_跳出循环_09


至此,我们的整个解析配置类上的ComponentScan注解的流程就算完毕了。


阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Spring