Spring学习之@Configuration
文章目录
@Configuration是什么?
@Configuration 是 Spring提供的一个用于配置与声明Bean与相应Bean之间依赖的注解,根据文档描述,此注解通常由 AnnotationConfigApplicationContext 上下文进行启动加载


@Configuration能做什么?

先看一下此注解的声明,在此注解上标识了 @Component ,则证明此注解是一个 Component,拥有 @Component
注解的基础能力(可以被Spring容器自动扫描与加载)
上图标识了注解常用的配置方式,分类为以下几种
- 属性资源导入
- 引入其它配置类的配置
- Value注入
- Spring容器组件注入
- 支持Profile配置
注解属性
在Spring5.x版本中,只支持两个属性配置
value
配置注解的名称
proxyBeanMethods
是否代理增强(基于CGLIB)标识 @Bean 的方法,默认为true,保证声明的bean是单例共享的,而不是每一次通过方法调用都生成一个新的

此属性的两个值被定义为两种模式
- full 模式(值为true)
- lite 模式(值为false)
源码分析
@Configuration
注解的解析类为 ConfigurationClassPostProcessor ,本次主要关注从 AnnotationConfigApplicationContext
启动后的整个处理过程, AnnotationConfigApplicationContext
启动分为三个阶段

先上一张三个阶段的涉及的主要类与调用关系图
初始化
初始化reader
此过程会实例化 AnnotatedBeanDefinitionReader
类,此类在实例化时会调用 AnnotationConfigUtils.registerAnnotationConfigProcessors
来注册解析配置的Processor,如果registry中没有包含 ConfigurationClassPostProcessor
类的定义,则会新new一个 ConfigurationClassPostProcessor
的Bean定义类

整体调用链路如下:

初始化scanner
此过程会实例化Bean定义扫描器 ClassPathBeanDefinitionScanner
, 在此过程中主要会设置 Environment 和 ResourceLoader 相关信息
注册
注册阶段主要是对标注了 @Configuration
类(MyConfig)进行注册,以便Spring可以正常识别,主要逻辑在 AnnotatedBeanDefinitionReader#doRegisterBean
中,此方法会调用 BeanDefinitionReaderUtils.registerBeanDefinition
对此Bean进行注册

至此,
@Configuration
类信息就注册到了 Spring 容器中
此阶段涉及Bean定义相关的类
- AnnotatedGenericBeanDefinition
- BeanDefinitionHolder
刷新
进入到最后的刷新阶段,Spring中对Bean的加工与处理都在这里进行,在此方法中主要关注 invokeBeanFactoryPostProcessors
方法,此方法会调用所有实现了 BeanFactoryPostProcessor
接口的类

配置@Bean方法返回的实例注册解析
在 @Configuration
类中配置的Bean定义会在 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()) 调用后被注册解析,此方法会调用所有Processor实现类的 postProcessBeanDefinitionRegistry
方法,对于 ConfigurationClassPostProcessor
则会在 processConfigBeanDefinitions
方法中完成对所有配置的Bean进行加载与注册

Bean增强
此过程是通过调用 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(registryProcessors, beanFactory)
来实现的

这时在初始化阶段实例化的 ConfigurationClassPostProcessor
类的 postProcessBeanFactory
方法就会被调用,在此方法中会通过调用 enhanceConfigurationClasses
方法对定义的Bean进行增强操作, 在此方法中通过委托 ConfigurationClassEnhancer
类的 enhance 方法对类进行增强, 在enhance 方法会创建一个新的 CGLIB的Enhancer类,Enhancer类创建后会通过调用 createClass 方法对类注册回调策略,其中一个回调为 BeanMethodInterceptor
, 在此类的 intercept() 方法进行真正的代理类创建




疑问
Configuration的属性是哪解析的?
解析发生在 ConfigurationClassPostProcessor
的 postProcessBeanDefinitionRegistry
阶段,此方法调用了 processConfigBeanDefinitions
方法,然后 processConfigBeanDefinitions
调用 ConfigurationClassUtils#checkConfigurationClassCandidate
方法对配置的属性进行检查判断与存储


full模式与lite模式的应用?
- 只是简单的配置时,可以使用lite模式,不需要生成相应的代理类,速度更快
- 对于复杂的配置,各定义Bean配置之间有依赖的需要直接调用Bean定义的方法且调用返回的都是同一个Bean时就需要使用通过Spring增强的full模式
REF
Using the @Configuration annotation
- When beans have dependencies on one another, expressing that dependency is as simple as having one bean method call another
- All @Configuration classes are subclassed at startup-time with CGLIB. In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance.