本文详解AnnotatedBeanDefinitionReader解析内置处理器为BeanDefinition并注册的全过程。
文章目录
前言
前文提到AnnotationConfigApplicationContext的构造器中调用三个方法,第一个是this(),this()的第一步是创建一个BeanFactory,this()的第二步是创建一个reader,第三步是创建一个scanner。
本文详解第二步。
一、 注册内置BeanPostProcessor
这是全系列文章中第一次提到后置处理器,这里不会太难,如果看不懂,可以先顺一遍,后边一定要回顾,这是Spring的核心。
跟着this()跟到AnnotatedBeanDefinitionReader的构造器,直接看最后一行代码,意思非常清楚,注册注解配置类的处理器。
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
进入
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
再进入,之后有一些关键的代码,我列出部分,不是说别的都不重要,而是,我列出的部分已经可以串成一条线。
1.判断是否已注册配置类的注解处理器
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
Spring的命名非常完整,可以清楚的看明白他的意图。
本段代码就是说如果还没有注册处理器,那么就注册他。
不要把处理器看的太过于复杂,他也是个类,在Spring容器中,他也需要先被解析成BeanDefinition,然后被注册。只不过处理器是由容器统一调用的,而我们的类是我们自己调用的。
ConfigurationClassPostProcessor是用于解析 @configuration注解的。
2.判断是否已注册自动装配的注解处理器
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
3.我要忽略其他部分
如果读者同时也在跟源码,那么会发现后边就是事件监听的处理器注册。绝对非常重要,但是,不在我们这条线上,我后边监听器部分会串另一条线,这里解释一下,让读者了解我的写作风格。
二、 注册相关的BeanDefinition
进入注册后置处理器的方法中。
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}
可以看到注册BeanDefiniton的调用。
跟进去的时候发现这是个接口的方法,他的实现类是GenericApplicationContext,这是注解容器AnnotationConfigApplicationContext的父类。
进入,可以看到就一句,向beanFactory注册BeanDefiniton。
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
再进入,会发现里面有大量的处理各种逻辑分支,各种异常的代码,但是最重要的只有两句。
//向map中注入<beanName, beanDefinition>的映射
this.beanDefinitionMap.put(beanName, beanDefinition);
//向set中注入beanName元素
this.beanDefinitionNames.add(beanName);
总结
Spring源码就像迷宫,如果你能拿到一幅地图,走出来实在太轻松了,因为他里面的命名实在太清楚了。但是,所有的课程书籍都会说,一定要抓住主线,其实也是我前边想传递的一个想法。就以事件监听器部分为例,确实很重要,但是在我们这条主线上,也是可以不看的,那就先不看。