基于 Spring Framework v5.2.6.RELEASE
概述
上一篇中介绍了@Component
注解,被它标记的类会被 Spring 的组件扫描逻辑筛选出来生成对应的 BeanDefinition,另外,@
Controller
、@Service
、@
Repository
注解标记的类型也会被筛选,因为这几个注解都被标记了@Component
元注解。除此之外,还有一个常见的注解@
Configuration
会被 Spring 扫描到,它不仅用来生成 BeanDefinition,还用来进行 Spring 应用的配置。
本文主要分析@
Configuration
中的配置是如何被读取和执行的。
@
Configuration
注解
注解@
Configuration
的源码如下。
ElementType.TYPE) (RetentionPolicy.RUNTIME) (public@interfaceConfiguration { annotation=Component.class) (Stringvalue() default""; booleanproxyBeanMethods() defaulttrue; }
因为它也被标记了@Component
注解,因此,标记了@
Configuration
注解的类也会被 Spring 识别到,并且生成其对应的 BeanDefinition。不过,@
Configuration
的作用并非是用来配置 BeanDefinition 的,而是可以像一个 XML 配置文件一样,配置 Bean 的信息,或者其他的一些配置。
比如,可以如下这样配置一个单例 Bean 极其创建的逻辑:
publicclassUserConfig { publicUseruser() { returnnewUser(); } }
然后,便可以在上下文中获取到名为user的对象。
publicclassMain { publicstaticvoidmain(String[] args) { ApplicationContextcontext=newAnnotationConfigApplicationContext("com.pseudocode.labs"); Useruser= (User)context.getBean("user"); user.sayHello(); } }
在 Spring 扫描包路径的时候,只会将扫描到的类型创建成对应的 BeanDefinition 并注册到容器中,那么,这里的配置是如何被加载到 Spring 容器中的呢?
后处理器的注册
这里需要回顾一下之前文章的内容,在《Spring 源码阅读 31:基于注解初始化 Spring 上下文的原理(1) 》中,曾经分析过,AnnotationConfigApplicationContext 初始化时,会初始化一个 AnnotatedBeanDefinitionReader 对象,初始化的过程中,会调用 AnnotationConfigUtils 的registerAnnotationConfigProcessors
方法,其中,会向容器中注册一些后处理器类,这里面就包含了处理被标记了@
Configuration
的类型的后处理器 ConfigurationClassPostProcessor。
// org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinitiondef=newRootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); }
我们看一下 ConfigurationClassPostProcessor 的继承关系。
这里可以注意到两点:
- 它实现了 BeanDefinitionRegistryPostProcessor 接口,而 BeanDefinitionRegistryPostProcessor 继承了 BeanFactoryPostProcessor,因此,它是一个处理 BeanFactory 的后处理器。这一点需要留意,后面会涉及到。
- 它实现了 PriorityOrdered 及 Ordered 接口,因此可以为它指定优先级和执行顺序。
至此可以得到结论,AnnotationConfigApplicationContext 默认包含了一个后处理器,能够处理被@
Configuration
标记的类型中的配置内容,那么接下来的问题就是,这个后处理器中的处理方法是什么时候执行的?
后处理器的执行
在 Spring 初始化上下文的过程中,当处理完准备工作之后,会通过调用refresh方法进入到核心流程中,refresh方法被定义在 AbstractApplicationContext 抽象类中,也就是说,所有继承了 AbstractApplicationContext 的上下文类型的上下文类型,都执行了同样的refresh方法,包括基于注解的上下文类型 AnnotationConfigApplicationContext 和基于 XML 配置文件的上下文类型 ClassPathXmlApplicationContext。
在refresh
方法中,完成 BeanFactory 的创建和预处理之后,会执行 BeanFactory 的后处理逻辑,具体对应 AbstractApplicationContext 的invokeBeanFactoryPostProcessors
方法,具体的执行步骤,被委托给了 PostProcessorRegistrationDelegate 的invokeBeanFactoryPostProcessors
方法。
具体的执行逻辑,在之前的源码分析文章中有过详细的介绍,可以参考:Spring 源码阅读 13:执行 BeanFactoryPostProcessor 中的处理方法 。
具体到 ConfigurationClassPostProcessor 后处理器,前面提到它实现了 BeanDefinitionRegistryPostProcessor,因此,它的postProcessBeanDefinitionRegistry
方法会被先执行,之后它的postProcessBeanFactory
会被执行。
因此,对@
Configuration
标记的类型的处理都在这两个方法只中了。
总结
本文梳理了@
Configuration
标记的配置类的配置信息,是由其对应的 BeanFactory 后处理器负责执行的,这个后处理器在上下文创建时被注册到容器中,当容器的预处理了完成后会执行其中的后处理方法。之后的文章,会进入 ConfigurationClassPostProcessor 中,详细分析两个处理方法。