@Configuration注解 -【Spring底层原理】

一、注解用法

1. 知识背景

  • lite @Bean mode :当@Bean方法在没有使用@Configuration注解的类中声明时称之为lite @Bean mode
  • Full @Configuration:如果@Bean方法在使用@Configuration注解的类中声明时称之为Full @Configuration

Full @Configuration中的@Bean方法会被CGLIB所代理,而 lite @Bean mode中的@Bean方法不会被CGLIB代理

2. @Configuration注解作用

  1. 告诉spring这是一个配置类,相当于spring的xml配置文件
  2. 被@Configuration 注解的类,会被cglib代理进行增强
  3. @Configuration类允许通过调用同一类中的其他@Bean方法来定义bean之间的依赖关系,保证@Bean的对象作用域受到控制,避免多例

二、实例分析

1. 案例

为了说明@Configuration注解的作用,我们先来看一个maven创建的spring项目

// 启动类
public class MainTest {
    @Test
    public void TestMain(){
        new AnnotationConfigApplicationContext(AppConfig.class);
    }
}

// 配置类
@Configuration
public class AppConfig {
    @Bean
    public User user(){
        return new User();
    }

    @Bean
    public User2 user2() {
        user();
        return new User2();
    }
}

// 两个实体类
public class User {
    public User() {
        System.out.println("User对象");
    }
}
public class User2 {
    public User2() {
        System.out.println("User2对象");
    }
}

这是一个最简单的spring项目,在配置类中有@Configuration注解,我们运行启动类,可以看到如下打印信息:

image-20210115101414931

如果去掉配置类中的@Configuration注解会怎样呢,去掉之后,咱们来看看打印信息:

image-20210115101618212

分析:

  • 在上面的代码中,并没有直接调用配置类和实体类,说明这些都在spring底层进行了封装
  • 在配置类中User类是进行了两次实例化的,但加了@Configuration注解后,只进行一次实例化,说明@Configuration注解将@Bean的方法进行的增强,保证实例为单实例

2. 问题

问1:@Configuration注解是如何定义bean之间的依赖关系?

问2:@Configuration注解是如何将@Bean方法进行增强的?

下面将跟踪spring源码来回答这两个问题

三、源码追踪

启动类代码只有AnnotationConfigApplicationContext类,所以咱们以这里为入口,点进去可以看到源码如下:

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
    this.register(componentClasses);
    this.refresh();
}

在这段源码中

  • this():这个无参构造是和bean相关的
  • register(componentClasses):将componentClasses注册到beanDefinitionMap集合中去
  • refresh():和@Configuration注解相关

所以咱们跟踪refresh(),点进去查看源码:

AbstractApplicationContext类中refresh方法】

public void refresh() throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
        this.prepareRefresh();
        // 告诉子类加载内部bean工厂
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        // 准备在上下文中使用的bean工厂
        this.prepareBeanFactory(beanFactory);

        try {
            // 允许在上下文子类中对bean工厂进行后置处理
            this.postProcessBeanFactory(beanFactory);
            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
            // 这个方法是源码分析里面比较重要的一个入口,这里只讲和@Configuration注解相关的
            // 解析@Configuration配置类,将自定义的BeanFactoryPostProcessor、BeanPostProcessor注册到beanDefinitionMap
            this.invokeBeanFactoryPostProcessors(beanFactory);
            // 将BeanPostProcessor实例化成bean并注册到beanFactory的beanPostProcessors
            this.registerBeanPostProcessors(beanFactory);
            beanPostProcess.end();
            // 注册国际化相关的Bean
            this.initMessageSource();
            // 为上下文注册应用事件广播器(用于ApplicationEvent的广播),如果有自定义则使用自定义的,如果没有则内部实例化一个
            this.initApplicationEventMulticaster();
            this.onRefresh();
            // 注册所有(静态、动态)的listener,并广播earlyApplicationEvents
            this.registerListeners();
            // 实例化用户自定义的普通单例Bean
            this.finishBeanFactoryInitialization(beanFactory);
            this.finishRefresh();
        } catch (BeansException var10) {
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
            }

            // 销毁已经创建的单例,以避免悬浮资源
            this.destroyBeans();
            this.cancelRefresh(var10);
            throw var10;
        } finally {
            // 在Spring的核心中重置公共缓存
            this.resetCommonCaches();
            contextRefresh.end();
        }

    }
}

上面的源码给出了部分注释,我们可以看到,和@Configuration注解相关的是invokeBeanFactoryPostProcessors方法,咱们继续跟踪,点进去看源码:

AbstractApplicationContext类中invokeBeanFactoryPostProcessors方法】

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // getBeanFactoryPostProcessors(): 拿到当前应用上下文beanFactoryPostProcessors变量中的值
    // invokeBeanFactoryPostProcessors: 实例化并调用所有已注册的BeanFactoryPostProcessor
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
    if (!IN_NATIVE_IMAGE && beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

继续跟踪invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors()),进入源码查看:

PostProcessorRegistrationDelegateinvokeBeanFactoryPostProcessors方法】

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    Set<String> processedBeans = new HashSet();
    ArrayList regularPostProcessors;
    ArrayList registryProcessors;
    int var9;
    ArrayList currentRegistryProcessors;
    String[] postProcessorNames;
    // 判断beanFactory是否为BeanDefinitionRegistry,beanFactory为DefaultListableBeanFactory
    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
        // 用于存放普通的BeanFactoryPostProcessor
        regularPostProcessors = new ArrayList();
        // 用于存放BeanDefinitionRegistryPostProcessor
        registryProcessors = new ArrayList();
        Iterator var6 = beanFactoryPostProcessors.iterator();

        // 遍历所有的beanFactoryPostProcessors, 将BeanDefinitionRegistryPostProcessor和普通BeanFactoryPostProcessor区分开
        while(var6.hasNext()) {
            BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var6.next();
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor)postProcessor;
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            } else {
                regularPostProcessors.add(postProcessor);
            }
        }

        currentRegistryProcessors = new ArrayList();
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        String[] var16 = postProcessorNames;
        var9 = postProcessorNames.length;

        int var10;
        String ppName;
        // 遍历postProcessorNames
        for(var10 = 0; var10 < var9; ++var10) {
            ppName = var16[var10];
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }

        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        // 解析配置类,为配置中的bean定义生成对应beanDefinition,并注入到registry的beanDefinitionMap
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
        currentRegistryProcessors.clear();
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        var16 = postProcessorNames;
        var9 = postProcessorNames.length;

        for(var10 = 0; var10 < var9; ++var10) {
            ppName = var16[var10];
            if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }

        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
        currentRegistryProcessors.clear();
        boolean reiterate = true;

        while(reiterate) {
            reiterate = false;
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            String[] var19 = postProcessorNames;
            var10 = postProcessorNames.length;

            for(int var26 = 0; var26 < var10; ++var26) {
                String ppName = var19[var26];
                if (!processedBeans.contains(ppName)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                    reiterate = true;
                }
            }

            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
            currentRegistryProcessors.clear();
        }

        // 调用ConfigurationClassPostProcessor#postProcessBeanFactory增强配置类
        // 通过cglib生成增强类,加载到jvm内存
        // 设置beanDefinition的beanClass为增强类,让@Bean生成的bean是单例
        invokeBeanFactoryPostProcessors((Collection)registryProcessors, (ConfigurableListableBeanFactory)beanFactory);
        invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    } else {
        invokeBeanFactoryPostProcessors((Collection)beanFactoryPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    }

    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
    regularPostProcessors = new ArrayList();
    registryProcessors = new ArrayList();
    currentRegistryProcessors = new ArrayList();
    postProcessorNames = postProcessorNames;
    int var20 = postProcessorNames.length;

    String ppName;
    for(var9 = 0; var9 < var20; ++var9) {
        ppName = postProcessorNames[var9];
        if (!processedBeans.contains(ppName)) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                regularPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
            } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                registryProcessors.add(ppName);
            } else {
                currentRegistryProcessors.add(ppName);
            }
        }
    }

    sortPostProcessors(regularPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList(registryProcessors.size());
    Iterator var21 = registryProcessors.iterator();

    while(var21.hasNext()) {
        String postProcessorName = (String)var21.next();
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }

    sortPostProcessors(orderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors((Collection)orderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList(currentRegistryProcessors.size());
    Iterator var24 = currentRegistryProcessors.iterator();

    while(var24.hasNext()) {
        ppName = (String)var24.next();
        nonOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
    }

    invokeBeanFactoryPostProcessors((Collection)nonOrderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    beanFactory.clearMetadataCache();
}

这里和@Configuration注解相关的方法是invokeBeanFactoryPostProcessors((Collection)registryProcessors, (ConfigurableListableBeanFactory)beanFactory);,继续跟踪,进入源码查看:

PostProcessorRegistrationDelegateinvokeBeanFactoryPostProcessors方法】

private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
    Iterator var2 = postProcessors.iterator();

    while(var2.hasNext()) {
        BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var2.next();
        StartupStep var10000 = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process");
        postProcessor.getClass();
        StartupStep postProcessBeanFactory = var10000.tag("postProcessor", postProcessor::toString);
        // 调用ConfigurationClassPostProcessor#postProcessBeanFactory增强配置类
        postProcessor.postProcessBeanFactory(beanFactory);
        postProcessBeanFactory.end();
    }
}

继续跟踪postProcessor.postProcessBeanFactory(beanFactory);,进入源码查看,发现是一个接口,咱们找到和@Configuration相关的,也就是截图中框出来的 ,查看源码:

image-20210115154241215

ConfigurationClassPostProcessor类中postProcessBeanFactory方法】

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    int factoryId = System.identityHashCode(beanFactory);
    if (this.factoriesPostProcessed.contains(factoryId)) {
        throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + beanFactory);
    } else {
        this.factoriesPostProcessed.add(factoryId);
        if (!this.registriesPostProcessed.contains(factoryId)) {
            this.processConfigBeanDefinitions((BeanDefinitionRegistry)beanFactory);
        }

        // 进行代理,为@Configuration注解的类生成增强类
        this.enhanceConfigurationClasses(beanFactory);
        beanFactory.addBeanPostProcessor(new ConfigurationClassPostProcessor.ImportAwareBeanPostProcessor(beanFactory));
    }
}

该方法会去判断我们的bean工厂当中是否有bean需要进行cglib代理,并在enhanceConfigurationClasses(beanFactory)方法中进行代理,为@Configuration注解的类生成增强类,继续跟踪,点进enhanceConfigurationClasses,如下:

ConfigurationClassPostProcessor类中enhanceConfigurationClasses方法】

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    StartupStep enhanceConfigClasses = this.applicationStartup.start("spring.context.config-classes.enhance");
    Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap();
    String[] var4 = beanFactory.getBeanDefinitionNames();
    int var5 = var4.length;

    for(int var6 = 0; var6 < var5; ++var6) {
        String beanName = var4[var6];
        BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
        // 在ConfigurationClassUtils中标记是Full @Configuration还是lite @Bean mode
        Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
        MethodMetadata methodMetadata = null;
        if (beanDef instanceof AnnotatedBeanDefinition) {
            methodMetadata = ((AnnotatedBeanDefinition)beanDef).getFactoryMethodMetadata();
        }

        if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
            AbstractBeanDefinition abd = (AbstractBeanDefinition)beanDef;
            if (!abd.hasBeanClass()) {
                try {
                    abd.resolveBeanClass(this.beanClassLoader);
                } catch (Throwable var13) {
                    throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), var13);
                }
            }
        }

        // 1.判断是否是全类注解
        if ("full".equals(configClassAttr)) {
            if (!(beanDef instanceof AbstractBeanDefinition)) {
                throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" + beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
            }

            if (this.logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
                this.logger.info("Cannot enhance @Configuration bean definition '" + beanName + "' since its singleton instance has been created too early. The typical cause is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor return type: Consider declaring such methods as 'static'.");
            }

            // 2.是全注解则将beandefinition放入map中
            configBeanDefs.put(beanName, (AbstractBeanDefinition)beanDef);
        }
    }

    if (!configBeanDefs.isEmpty() && !IN_NATIVE_IMAGE) {
        ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
        Iterator var15 = configBeanDefs.entrySet().iterator();

        // 3.然后遍历这个map
        while(var15.hasNext()) {
            Entry<String, AbstractBeanDefinition> entry = (Entry)var15.next();
            AbstractBeanDefinition beanDef = (AbstractBeanDefinition)entry.getValue();
            beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
            Class<?> configClass = beanDef.getBeanClass();
            // 4.进行cglib代理,为@Configuration注解的类生成增强类
            Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
            if (configClass != enhancedClass) {
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
                }

                // 再通过beanDef.setBeanClass(enhancedClass)修改beanDefinition的BeanClass属性,
                // 在bean实例化阶段,会利用反射技术将beanClass属性对应的类实例化出来
                // 所以最终实例化出来的@Configuration bean是一个代理类的实例
                beanDef.setBeanClass(enhancedClass);
            }
        }

        enhanceConfigClasses.tag("classCount", () -> {
            return String.valueOf(configBeanDefs.keySet().size());
        }).end();
    } else {
        enhanceConfigClasses.end();
    }
}

ConfigurationClassUtils类中声明了是Full @Configuration还是lite @Bean mode,可以看看源码:

ConfigurationClassUtils类中checkConfigurationClassCandidate方法】

Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
// 如果存在@Configuration注解,则为BeanDefinition设置configurationClass属性为full
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, "full");
} else {
    if (config == null && !isConfigurationCandidate(metadata)) {
        return false;
    }

    // 如果没有@Configuration注解或者有Component,ComponentScan,Import,ImportResource 注解中的任意一个,
    // 或者存在 被@bean 注解的方法,则返回true.
    // 则设置configurationClass属性为lite
    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, "lite");
}

Integer order = getOrder(metadata);
if (order != null) {
    beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}

跟踪到这里,基本上就比较明朗了,可以得到我们想要的答案

  1. ConfigurationClassUtils类中的checkConfigurationClassCandidate标记是Full @Configuration还是lite @Bean mode
  2. 通过"full".equals(configClassAttr)判断是否是全类注解
  3. 是全注解则将beandefinition放入map中configBeanDefs.put
  4. 遍历这个map
  5. 使用cglib技术为配置类生成一个enhancedClass
  6. 通过enhancer.enhance进行cglib代理,为@Configuration注解的类生成增强类
  7. 再通过beanDef.setBeanClass(enhancedClass)修改beanDefinition的BeanClass属性,在bean实例化阶段,会利用反射技术将beanClass属性对应的类实例化出来,所以最终实例化出来的@Configuration bean是一个代理类的实例

使用了@Configuration注解的类,属于Full @Configuration。@Configuration类允许通过调用同一类中的其他@Bean方法来定义bean之间的依赖关系,保证@Bean的对象作用域受到控制,避免多例。@Configuration类中的@Bean地方会被CGLIB进行代理。Spring会拦截该方法的执行,在默认单例情况下,容器中只有一个Bean,所以我们多次调用user()方法,获取的都是同一个对象。

对于@Configuration注解的类中@Bean标记的方法,返回的都是一个bean,在增强的方法中,Spring会先去容器中查看一下是否有这个bean的实例了,如果有了的话,就返回已有对象,没有的话就创建一个,然后放到容器中。

是如何进行代理的,咱们还可以继续跟踪:点开enhancer.enhance,进入ConfigurationClassEnhancer类,在这个类中会去执行cglib代理类中的代理方法,如下:

ConfigurationClassEnhancer类中static静态方法】

static {
    CALLBACKS = new Callback[]{new ConfigurationClassEnhancer.BeanMethodInterceptor(), 
                               new ConfigurationClassEnhancer.BeanFactoryAwareMethodInterceptor(), NoOp.INSTANCE};
    CALLBACK_FILTER = new ConfigurationClassEnhancer.ConditionalCallbackFilter(CALLBACKS);
    logger = LogFactory.getLog(ConfigurationClassEnhancer.class);
    objenesis = new SpringObjenesis();
}

cglib代理主要就是callBacks中的方法,点进去可以看到是一个接口,其中有一个实现类就是和cglib相关的

image-20210115201141656

四、总结

@Configuration注解底层是如何实现的,通过源码咱们可以反推并总结为以下几点:

  1. Spring首先会获取到所有的beandefenition
  2. ConfigurationClassUtils类中checkConfigurationClassCandidate方法判断是Full @Configuration还是lite @Bean mode
  3. 通过ConfigurationClassPostProcessor后置处理器遍历所有的beandefenition
  4. 将标记了Full @Configuration模式的beandefenition,会对这个类进行cglib代理,生成一个代理类,并把这个类设置到BeanDefenition的Class属性中
    1. 配置类会被CGLIB增强(生成代理对象),放进IoC容器内的是代理
    2. 对于内部类是没有限制的:可以是Full模式或者Lite模式
    3. 配置类内部可以通过方法调用来处理依赖,并且能够保证是同一个实例,都指向IoC内的那个单例
  5. 需要用这个Bean实例的时候,从这个Class属性中拿到的Class对象进行反射,最终反射出来的是代理增强后的类
  6. 通过@Configuration标注类的Bean,Spring会先去容器中查看是否有这个Bean实例,如果有就返回已有的对象,没有就创建一个,然后放到容器中
end
  • 作者:ONESTAR(联系作者)
  • 更新时间:2021-01-18 09:26
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 转载声明:如果是转载栈主转载的文章,请附上原文链接
  • 公众号转载:请在文末添加作者公众号二维码(公众号二维码见右边,欢迎关注)
  • 评论

    新增邮件回复功能,回复将会通过邮件形式提醒,请填写有效的邮件!