目录
2、processConfigBeanDefinitions()
4、doProcessConfigurationClass()
ConfigurationClassPostProcessor是用来容器启动时处理解析容器的配置类,实现了BeanDefinitionRegistry、PriorityOrdered接口。
当容器开启组件扫描或使用ComponentScan会默认注册到容器中,否则,将如同其他的BeanFactoryPostProcessor后置处理器一样手动被声明到容器中。
配置类通过ConfigurationClassUtils工具类判断:
1、标识@Configuration注解
2、标识@Component、@ComponentScan、@Import、@ImportResource、方法标识@Bean
创建容器时,在refresh方法中调用invokeBeanFactoryPostProcessors方法创建运行BeanFactory后置处理器。
进入invokeBeanFactoryPostProcessors方法的PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法, ConfigurationClassPostProcessor由于实现了BeanDefinitionRegistry、PriorityOrdered接口,在如图红框被容器扫描出来并创建对象,在invokeBeanDefinitionRegistryPostProcessors方法中运行ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法。
ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法主要是设置registryId,防止postProcessBeanDefinitionRegistry方法被多次调用,processConfigBeanDefinitions方法开始解析配置类。
在processConfigBeanDefinitions方法中遍历容器的beanDefinition集合,通过ConfigurationClassUtils工具类找到配置类beanDefinition,将其放入configCandidates集合中。
创建ConfigurationClassParser对象,调用对象的parse方法对配置类进行解析。
进入parse方法,根据bd的类型进入不同的parse方法,而那些parse方法都调用一个processConfigurationClass方法。
先根据配置类是否标识了@Conditional,判断是否跳过不解析。
通过doProcessConfigurationClass方法对配置类信息进行详细解析,若是当前配置类含有父类(排除java开头的类,例如Object),则会返回该配置类的父类,进行对父类进行解析,然后最后将已解析的配置类放到configurationClasses集合中,防止多次解析。
该方法主要是解析多个spring注解,例如@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean、解析配置类的内部类等。
进入doProcessConfigurationClass方法,先判断该配置类是否含有@Component注解(isAnnotated方法会找当前类标识的注解,包括注解内部的元注解),
若是有,则通过processMemberClasses方法会遍历配置类定义的内部类,判断内部类是否是配置类,若是则将内部类放入candidates集合中,并遍历candidates集合调用processConfigurationClass方法解析。
- private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
- Collection
memberClasses = sourceClass.getMemberClasses(); - if (!memberClasses.isEmpty()) {
- List
candidates = new ArrayList<>(memberClasses.size()); - for (SourceClass memberClass : memberClasses) {
- if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
- !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
- candidates.add(memberClass);
- }
- }
- OrderComparator.sort(candidates);
- for (SourceClass candidate : candidates) {
- if (this.importStack.contains(configClass)) {
- this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
- }
- else {
- this.importStack.push(configClass);
- try {
- processConfigurationClass(candidate.asConfigClass(configClass));
- }
- finally {
- this.importStack.pop();
- }
- }
- }
- }
- }
接着解析配置类的@PropertySource,解析配置文件并加载到容器环境中。
解析@ComponentScan组件,扫描得到beanDefinition集合,若是扫描中包含配置类,则会调用parse方法先解析该配置类
接下来解析@Import组件,解析详情可参考解析@Import底层原理_Just-Today的博客-CSDN博客
解析@ImportResource
解析@Bean
最后判断该配置类是否继承类名不是java开头的父类,且父类不在knownSuperclasses集合中,若是有则返回该配置类的父类,继续解析父类,若是没,则返回null结束解析循环方法。
至此,通过解析将容器中的所有配置类、通过解析注解得到的beanDefinition都被保存到容器的beanDefinitions集合中。