Spring解析@ComponentScan注解的执行流程
Posted 默辨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring解析@ComponentScan注解的执行流程相关的知识,希望对你有一定的参考价值。
文章目录
- 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、总体的执行流程图
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)方法
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注解
下图为该方法的部分执行逻辑:(注意ConfigurationClassPostProcessor类,实现了PriorityOrdered接口)
1、创建一个集合用于存放即将要处理的BeanDefinitionRegistryPostProcessor
2、根据接口类型去获取类
3、校验是否实现了PriorityOrdered接口
4、将数据添加到对应的集合中
5、将集合中的内容进行排序
6、依次执行注册接口对应的方法
4、ConfigurationClassPostProcessor类的processConfigBeanDefinitions方法
在该方法中,Spring会获取我们在实例化AnnotationConfigApplicationContext类时候传入的参数,然后对类进行判断,符合条件的配置类会添加到一个list集合中。在配置类不为空的情况下,会去创建一个ConfigurationClassParser对象,用来解析我们传入的配置类。
图中主要流程为:
1、传入指定的配置类集合,进行解析(解析类上的注解,此处就包括了我们的@ComponentScan注解)
2、对相关内容进行校验
3、通常配置类中还有@Bean定义的Bean、使用@ImportResource导入xml文件中定义的Bean等。调用loadBeanDefinitions方法,就会将这些Bean,添加到BDMap中,在parse方法中也进行了扫描处理,但是那一步仅仅把它们添加到了对应的集合中,没有添加到BDMap中
补充:
此处使用了一个do while循环来处理配置类,而不是直接执行方法,为的是避免我们在解析配置类的时候,可能配置类内部定义的Bean也是一个配置类。只有当我们解析出来的配置类都被解析以后,我们才会真正的跳出循环,即对应配置类的解析操作才算完成
5、ConfigurationClassParser类的parse方法
根据我们传入配置类的不同类型,再调用对应的parse方法
6、ConfigurationClassParser类的processConfigurationClass方法
7、最终的doProcessConfigurationClass方法
该方法中会解析各种注解,其中就包含了我们本次博客的重点@ComponentScan注解
8、扫描BD方法doScan
上一步的parse方法,会调用ComponentScanAnnotationParser类的parse方法,然后调用scanner.doScan(StringUtils.toStringArray(basePackages))方法,完成对应的扫描操作。
在doScan方法中,主要行为为:
1、basePackages:遍历传入进来的路径数组
2、findCandidateComponents:扫描指定路径下所有符合要求的类
3、registerBeanDefinition:将符合要求的类封装成BD的形式,添加到对应的集合中
具体的如何根据路径获取符合要求的类,可以参考我之前的博客:获取指定路径,扫描路径下指定类(仿Spring)
至此,我们的整个解析配置类上的ComponentScan注解的流程就算完毕了。
以上是关于Spring解析@ComponentScan注解的执行流程的主要内容,如果未能解决你的问题,请参考以下文章
Spring注解详解:@ComponentScan自动扫描组件使用
Spring注解驱动开发第4讲——自定义TypeFilter指定@ComponentScan注解的过滤规则