Spring源码分析:@Configuration是如何实现代码增强的

@Configuration源码分析

  • @Configuration介绍
  • 代码示例
  • @Configuration类如何实现代理
    • @Configuration在哪一步变成代理对象
    • 调用后置处理器
    • 调用@Configuration注解的后置处理器
    • "full"模式 or "lite"模式
    • ConfigurationClassUtils
    • 创建代理对象
    • 为什么无法下载org.springframework.cglib包源码

@Configuration介绍

Spring官方文档对@Configuration的介绍:

@Configuration is a class-level annotation indicating that an object is a source of bean definitions. @Configuration classes declare beans via public @Bean annotated methods. Calls to @Bean methods on @Configuration classes can also be used to define inter-bean dependencies.

@Configuration是类级别的注解,指示一个对象是Bean定义(Bean Definition)的来源。@Configuration类通过公共@Bean注释方法声明Bean。@Configuration类允许通过调用同一个类的其他@Bean方法来定义Bean的依赖关系。

代码示例

public class ConfigurationBean {
}

public interface ConfigurationService {
    public void test(ConfigurationBean configurationBean);
}

public class ConfigurationServiceImpl implements ConfigurationService {

    public ConfigurationServiceImpl(ConfigurationBean configurationBean) {
        System.out.println("ConfigurationServiceImpl====" + configurationBean);
    }

    @Override
    public void test(ConfigurationBean configurationBean) {
        System.out.println("test====" + configurationBean);
    }
}

@Configuration
public class AppConfiguration {

    @Bean
    public ConfigurationService configurationService() {
        return new ConfigurationServiceImpl(configurationBean());
    }

    @Bean
    public ConfigurationBean configurationBean() {
        return new ConfigurationBean();
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfiguration.class);
//     System.out.println(context.getBean("configurationService"));
    }
}

以上的代码等价于:

<beans>
    <bean id="configurationBean" class="ConfigurationBean"/>
    <bean id="configurationService" class="ConfigurationServiceImpl">
        <constructor-arg ref="configurationBean">constructor-arg> 
    bean>
beans>

@Bean注解用于指示方法实例化,配置和初始化要由Spring IoC容器管理的新对象。@ Bean注释与元素具有相同的作用。

@Configuration类如何实现代理

Spring源码分析:@Configuration是如何实现代码增强的_第1张图片
这里获取到的AppConfiguration是一个Cglib代理对象,那这个代理对象是如何生成的呢?

@Configuration在哪一步变成代理对象

进入AbstractApplicationContext的refresh方法,
Spring源码分析:@Configuration是如何实现代码增强的_第2张图片Spring源码分析:@Configuration是如何实现代码增强的_第3张图片
在执行invokeBeanFactoryPostProcessors(beanFactory)方法前是普通的AppConfiguration类,执行完invokeBeanFactoryPostProcessors方法后,AppConfiguration是一个增强过的Cglib代理对象。

调用后置处理器

AbstractApplicationContext.invokeBeanFactoryPostProcessors
Spring源码分析:@Configuration是如何实现代码增强的_第4张图片

调用@Configuration注解的后置处理器

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
currentRegistryProcessors是ConfigurationClassPostProcessor,是@Configuration类的后置处理器。
Spring源码分析:@Configuration是如何实现代码增强的_第5张图片
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry
Spring源码分析:@Configuration是如何实现代码增强的_第6张图片

"full"模式 or "lite"模式

ConfigurationClassPostProcessor.processConfigBeanDefinitions
Spring源码分析:@Configuration是如何实现代码增强的_第7张图片

ConfigurationClassUtils

(1)如果在未使用@Configuration注释的类中声明@Bean方法,则将它们在“lite”模式下进行处理。
(2)如果在使用@Configuration注释的类中声明@Bean方法,则将他们在"full"模式下进行处理。
(3)在"lite"模式下,无法声明Bean之间的依赖关系。在“full”模式下,跨方法引用将被重定向到容器的生命周期管理。也就是,如果类添加了@Configuration注解,类中的一个Bean方法A引用另一个Bean方法B,会到Spring容器中找B方法创建的Bean,而不是调用方法B再新创建一个Bean。
Spring源码分析:@Configuration是如何实现代码增强的_第8张图片
进入ConfigurationUtils的checkConfigurationClassCandidate方法,meta的类型是StandardAnnotationMetadata,判断meta是否标注了@Configuration注解。如果类标有@Configuration注解,该类对应的BeanDefinition的元数据会加上一个属性(org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass, full);
Spring源码分析:@Configuration是如何实现代码增强的_第9张图片
判断是否标注了@Configuration注解
在这里插入图片描述

创建代理对象

ConfigurationClassPostProcessor.enhanceConfigurationClasses

用ConfigurationClassEnhancer对AppConfiguration进行增强,如果父类configClass(class gdut.ff.configuration.AppConfiguration)与生成的子类(class gdut.ff.configuration.AppConfiguration E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIBf5d6df32)不一样的话,就将BeanDefinition中的beanClass的值设置为生成的代理对象(class gdut.ff.configuration.AppConfiguration E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIBf5d6df32)
Spring源码分析:@Configuration是如何实现代码增强的_第10张图片
ConfigurationClassEnhancer.enhancer方法用于创建AppConfiguration的一个cglib子类对象。
Spring源码分析:@Configuration是如何实现代码增强的_第11张图片
创建一个cglib实例
Spring源码分析:@Configuration是如何实现代码增强的_第12张图片
创建子类对象
Spring源码分析:@Configuration是如何实现代码增强的_第13张图片

为什么无法下载org.springframework.cglib包源码

今天断点看Spring源码的时候发现,无法找到org.springframework.cglib包下的代码,原来这部分代码是Spring打包的时候从net.sf.cglib拿来的,详情可以参看spring-core-5.0.6.RELEASE-sources.jar中java源代码不全

你可能感兴趣的:(Spring,spring,java)