@Configuration是什么?

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

@Configuration能做什么?

先看一下此注解的声明,在此注解上标识了 @Component ,则证明此注解是一个 Component,拥有 @Component 注解的基础能力(可以被Spring容器自动扫描与加载)

上图标识了注解常用的配置方式,分类为以下几种

  1. 属性资源导入
  2. 引入其它配置类的配置
  3. Value注入
  4. Spring容器组件注入
  5. 支持Profile配置

注解属性

在Spring5.x版本中,只支持两个属性配置

value

配置注解的名称

proxyBeanMethods

是否代理增强(基于CGLIB)标识 @Bean 的方法,默认为true,保证声明的bean是单例共享的,而不是每一次通过方法调用都生成一个新的

此属性的两个值被定义为两种模式

  1. full 模式(值为true)
  2. 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定义相关的类

  1. AnnotatedGenericBeanDefinition
  2. 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的属性是哪解析的?

解析发生在 ConfigurationClassPostProcessorpostProcessBeanDefinitionRegistry 阶段,此方法调用了 processConfigBeanDefinitions 方法,然后 processConfigBeanDefinitions 调用 ConfigurationClassUtils#checkConfigurationClassCandidate 方法对配置的属性进行检查判断与存储

full模式与lite模式的应用?

  1. 只是简单的配置时,可以使用lite模式,不需要生成相应的代理类,速度更快
  2. 对于复杂的配置,各定义Bean配置之间有依赖的需要直接调用Bean定义的方法且调用返回的都是同一个Bean时就需要使用通过Spring增强的full模式

REF

Using the @Configuration annotation

  1. When beans have dependencies on one another, expressing that dependency is as simple as having one bean method call another
  2. 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.