Bean的注册
在上一篇文章中提到了在使用invokeBeanFactoryPostProcessors(beanFactory)
方法中,
调用了 ConfigurationClassPostProcessor
中的 postProcessBeanDefinitionRegistry
方法,
实现了对configuration配置文件中的内容得到加载和解析。完成对标注为Bean的方法注册「regist」到容器中。
下面就针对这一注册配置文件内的Bean的过程进行源码的分析:
ConfigurationClassPostProcessor
在 invokeBeanFactoryPostProcessor
方法中,
循环调用类中的后置方法 postProcessBeanDefinitionRegistry
,
其中包括了 ConfigurationClassPostProcessor
类。
根据名字也能看出这个类是配置文件类的后置处理类。那么就之间看代码,了解配置文件的后置处理器都做了些什么。
1 | public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { |
下面对 processConfigBeanDefinitions 中的方法一步一步看:
使用processConfigBeanDefinitions解析注册Bean
1 | public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { |
上述代码完成了的过程大致分为这几步
- 找出Config配置类,包括使用@Configuration注解标注的配置类
- 根据@Order进行进行顺序的调整
- 解析所有的@Configuration内的Bean,完成对配置类中所有 Bean的注册。
- 验证并进行标记Bean已经被解析注册
其中最重要的就是第3步,需要找出Bean,并进行注册
parse方法解析并完成注册Bean的。
1 | public void parse(Set<BeanDefinitionHolder> configCandidates) { |
如果使用注解方式进行配置类的配置的情况,最后会调用 processConfigurationClass
方法进行处理。
1 | protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { |
最后会递归使用 doProcessConfigurationClass
进行处理配置类和其超类.
1 | protected final SourceClass doProcessConfigurationClass( |
总结在使用 doProcessConfigurationClass 方法时,大致会有这样几步:
- 如果标记有
@Component
注解,则会先去递归处理成员类,那么他是如何进行递归处理的呢,看主要方法的调用就能够理解:
processMemberClasses -> processConfigurationClass -> doProcessConfigurationClass -> processMemberClasses
每次都会递归的先处理成员类。 - 处理
@PropertySource
注解,作用为加载指定的配置文件 - 处理所有的
@ComponentScan
注解,如果配置文件中标记有@ComponentSacn
或者@ComponentScans
注解的话,会先去解析对应路径下的Bean,包装成BeanDefinitionHolder
再次进行parse。 - 处理所有的
@Import
注解,处理所有使用Import注解引入的配置文件 - 处理所有的
@ImportResource
注解 - 处理所有
@Bean
方法,添加为 BeanMethod,解析配置文件中配置为@Bean的方法,添加到configClass中的BeanMethod中 - 处理接口的默认方法
- 按照以上逻辑进行递归的处理超类。
在方法中,可以找时间画一张图来解析这个方法真正做了写什么。[todo] 。
注册的精简过程
最后的parse方法是关键,经过以上步骤可以,在本章节需要特别注意的是 @ComponentSacn 和 处理所有的 @Bean 这两步:
在处理 @ComponentSacn 中,将直接将根据路径解析出来的Bean使用 componentScanParser.parse
方法,最终在 registerBeanDefinition
() 方法中注册进去。
而在处理@Bean方法的时候,是将Bean方法包装成BeanMethod 放到 this.beanMethods
中,等待在 parse()
后 this.reader.loadBeanDefinitions(configClasses);
中进行操作.
而在前面说的loadBeanDefinitions 中会将前面提到的 Import、ImportReource和 BeanMethod 统一进行注册。
1 | if (configClass.isImported()) { |
在loadBeanDefinitionsForBeanMethod中,进行了对解析出来的使用@Bean标注的方法进行注册。从而完成注册Bean的主线功能。不具体进行梳理这个方法的过程,大致为构建一个BeanDefintion后,通过registerBeanDefinition方法进行注册,放到beanDefinitionMap中。