一、概述

@Bean 属于配置元注解。其他几个分别为

  • @Configuration
  • @Import
  • @DependsOn

后置处理器 org.springframework.context.annotation.ConfigurationClassPostProcessor 完成配置类解析操作,
与这些注解相配套的是org.springframework.context.annotation.ConfigurationClassPostProcessor后置处理器。他们负责处理这些与配置相关的注解。

二、@Bean

2.1 @Bean 预览

  1. @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public @interface Bean {
  5. @AliasFor("name")
  6. String[] value() default {};
  7. @AliasFor("value")
  8. String[] name() default {};
  9. @Deprecated
  10. Autowire autowire() default Autowire.NO;
  11. boolean autowireCandidate() default true;
  12. String initMethod() default "";
  13. String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
  14. }
  • name 为数组类型,可以同时存在多个名称。

    2.2 @Scope, @Lazy, @DependsOn, @Primary, @Order

    @Bean 可与 @Scope, @Lazy, @DependsOn, @Primary, @Order等注解完成特定的单例类配置。

    2.3 @Configuration 类中的 @Bean 方法

    通常,@bean 方法在@configuration 类中声明。在这种情况下,bean 方法可以通过直接调用引用同一类中的其他@bean 方法,确保单例作用域以及 AOP 语义。因为,带有 @Configuration 注解的配置类会被 CGLib 字节码提升,对内部方法进行动态代理。因此,在这种模式下,不能将@Configuration 的类标记为 finalprivate

    2.4 @Bean Lite 模式

    @Bean 也可以在没有使用 @Configuration 注解的类中声明,在这种情况下, @Bean 将会以所谓的 lite 模式进行处理,即不进行字节码提升。
    Lite 模式中的 @Bean 方法将会被容器视为普通的工厂方法,并且能正常地应用作用域以及 Spring 相关生命周期回调。但当另一个 @Bean 方法调用另一个 @Bean 方法时,调用的是标准的 Java 方法,而不是通过 CGLib 代理拦截方法调用,所以会产生不必要的异常。所以,请在配置类中写有 @Configuration 注解。

    2.5 静态方法的 @Bean

    对于返回 BeanFactoryPostProcessor(BFPP) 类型的 @Bean 方法,必须要特别考虑,因为 BFPP 对象必须在容器生命周期早期实例化,因为它会干扰 @Configuration 类中的 @Autowired@Value@PostConstruct 等注解的处理。为了避免引起不必要的错误,应该将方法设置为 static
    1. @Bean
    2. public static PropertyPlaceholderConfigurer ppc() {
    3. // instantiate, configure and return ppc ...
    4. }
    通过将此方法标记为静态,可以在不引发其声明的@Configuration 类的实例化的情况下调用它(也就是当前方法脱离当前的配置类),从而避免上述生命周期冲突。但是请注意,静态的 @Bean方法在作用域和 AOP 语义方面不会像上面提到的那样得到增强。这在 BFPP 情况下是可行的,因为其他@bean 方法通常不引用这些方法。作为提醒,将为任何具有可分配给 BeanFactoryPostProcessor的返回类型的非静态@bean 方法发出 warn 级日志消息。

    2.6 示例

    ```java public class A { @Override public String toString() {
    1. return "A";
    } }

@Configuration public class ConfigurationDemo { @Bean public A a() { return new A(); } public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(ConfigurationDemo.class); context.refresh();

    System.out.println(context.getBean(A.class));

    context.stop();
}

} // OUTPUT // A

<a name="tslVx"></a>
# 三、ConfigurationClassPostProcessor 源码分析
<a name="TUB8V"></a>
## 3.1 Spring 容器后置处理器调用栈
![configuration-proces.png](https://cdn.nlark.com/yuque/0/2020/png/105848/1600744175171-6213ce2f-c7b4-4971-a996-47fb438a03af.png#align=left&display=inline&height=628&margin=%5Bobject%20Object%5D&name=configuration-proces.png&originHeight=628&originWidth=1579&size=187284&status=done&style=none&width=1579)从上图可知,容器执行所有后置处理器是在`org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors(beanFactory)` 方法被调用。而 `ConfigurationClassPostProcessor` 则是用来解析我们的配置类。**<br />在此方法中,最重要的方法是`this.reader.loadBeanDefinitions(ConfigClasses)` ,它的任务是解析配置类,并注册相关的 `BeanDefinition` 。<br />![configurationClasspostprocessor-@Bean.png](https://cdn.nlark.com/yuque/0/2020/png/105848/1600770884689-a0ff281d-f94d-4289-aadf-a6f8f4511e6b.png#align=left&display=inline&height=681&margin=%5Bobject%20Object%5D&name=configurationClasspostprocessor-%40Bean.png&originHeight=681&originWidth=1367&size=169798&status=done&style=none&width=1367)<br />可以通过左下角的调用栈获取解析注解 `@Bean`的完整链路。<br />解析注解 `@Bean` ,就是让他变成 `BeanDefinition`(菜谱),供后续对他进行实例化。解析核心代码如下: 
```java
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
    ConfigurationClass configClass = beanMethod.getConfigurationClass();
    MethodMetadata metadata = beanMethod.getMetadata();
    String methodName = metadata.getMethodName();

    // Do we need to mark the bean as skipped by its condition?
    if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
        configClass.skippedBeanMethods.add(methodName);
        return;
    }
    if (configClass.skippedBeanMethods.contains(methodName)) {
        return;
    }

    AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
    Assert.state(bean != null, "No @Bean annotation attributes");

    // Consider name and any aliases
    List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
    String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

    // Register aliases even when overridden
    for (String alias : names) {
        this.registry.registerAlias(beanName, alias);
    }

    // Has this effectively been overridden before (e.g. via XML)?
    if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
        if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
            throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
                                                   beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
                                                   "' clashes with bean name for containing configuration class; please make those names unique!");
        }
        return;
    }
    // 根据配置元信息创建BeanDefinition
    ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
    beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

    if (metadata.isStatic()) {
        // @Bean注解在静态方法之上
        if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
            beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
        }
        else {
            beanDef.setBeanClassName(configClass.getMetadata().getClassName());
        }
        beanDef.setUniqueFactoryMethodName(methodName);
    }
    else {
        // instance @Bean method
        beanDef.setFactoryBeanName(configClass.getBeanName());
        beanDef.setUniqueFactoryMethodName(methodName);
    }

    if (metadata instanceof StandardMethodMetadata) {
        beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
    }

    beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
    beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
                         SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

    AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

    Autowire autowire = bean.getEnum("autowire");
    if (autowire.isAutowire()) {
        beanDef.setAutowireMode(autowire.value());
    }

    boolean autowireCandidate = bean.getBoolean("autowireCandidate");
    if (!autowireCandidate) {
        beanDef.setAutowireCandidate(false);
    }

    String initMethodName = bean.getString("initMethod");
    if (StringUtils.hasText(initMethodName)) {
        beanDef.setInitMethodName(initMethodName);
    }

    String destroyMethodName = bean.getString("destroyMethod");
    beanDef.setDestroyMethodName(destroyMethodName);

    // Consider scoping
    ScopedProxyMode proxyMode = ScopedProxyMode.NO;
    AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
    if (attributes != null) {
        beanDef.setScope(attributes.getString("value"));
        proxyMode = attributes.getEnum("proxyMode");
        if (proxyMode == ScopedProxyMode.DEFAULT) {
            proxyMode = ScopedProxyMode.NO;
        }
    }

    // Replace the original bean definition with the target one, if necessary
    BeanDefinition beanDefToRegister = beanDef;
    if (proxyMode != ScopedProxyMode.NO) {
        BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
            new BeanDefinitionHolder(beanDef, beanName), this.registry,
            proxyMode == ScopedProxyMode.TARGET_CLASS);
        beanDefToRegister = new ConfigurationClassBeanDefinition(
            (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
    }

    this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

四、附录

/**
     * 基于配置类的注册表构建和验证配置模型
     * 任务:解析用户的配置类(@Configuration)
     */
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    // #1 获取所有已注册的bean元信息
    String[] candidateNames = registry.getBeanDefinitionNames();

    // #2 循环遍历,只为找到配置类(Spring的配置类范围很大,不仅仅局限于使用注解@Configuration,也可以是@ComponentScan()、@Import等等)
    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
            // 2-1 判断是否已经确定当前类类类型
            if (logger.isDebugEnabled()) {
                logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
            }
        }
        // 2-2 检查给定的bean元信息是否为 配置类(或在配置/组件类中声明的嵌套组件类,也要自动注册)的候选类,并相应地对其进行标记
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            // 如果是配置类的话,会放到configCandidates集合,将配置类信息使用BeanDefinitionHolder包装并放在configCandiates集合里
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }

    // Return immediately if no @Configuration classes were found
    if (configCandidates.isEmpty()) {
        return;
    }

    // #3 根据@Order的值进行排序
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });

    // #4 检测通过封闭的应用程序上下文提供的任何自定义bean名称生成策略
    SingletonBeanRegistry sbr = null;
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        if (!this.localBeanNameGeneratorSet) {
            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
                AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
            if (generator != null) {
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator;
            }
        }
    }

    if (this.environment == null) {
        this.environment = new StandardEnvironment();
    }

    // #5 循环解析Bean元信息Map中的所有配置类。
    // 重点注解 @Import、@ComponentScan
    ConfigurationClassParser parser = new ConfigurationClassParser(
        this.metadataReaderFactory, this.problemReporter, this.environment,
        this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    do {
        // 重点△:5-1 解析候选者
        parser.parse(candidates);
        parser.validate();

        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        configClasses.removeAll(alreadyParsed);

        // Read the model and create bean definitions based on its content
        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                registry, this.sourceExtractor, this.resourceLoader, this.environment,
                this.importBeanNameGenerator, parser.getImportRegistry());
        }
        // 5-2 将配置类中的带@Bean的Bean元信息存放到beanDefinitionMap中
        this.reader.loadBeanDefinitions(configClasses);
        alreadyParsed.addAll(configClasses);

        candidates.clear();
        if (registry.getBeanDefinitionCount() > candidateNames.length) {
            String[] newCandidateNames = registry.getBeanDefinitionNames();
            Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
            Set<String> alreadyParsedClasses = new HashSet<>();
            for (ConfigurationClass configurationClass : alreadyParsed) {
                alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
            }
            for (String candidateName : newCandidateNames) {
                if (!oldCandidateNames.contains(candidateName)) {
                    BeanDefinition bd = registry.getBeanDefinition(candidateName);
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                        !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                        candidates.add(new BeanDefinitionHolder(bd, candidateName));
                    }
                }
            }
            candidateNames = newCandidateNames;
        }
    }
    while (!candidates.isEmpty());

    // #6 将ImportRegistry注册为Bean,以支持ImportAware @Configuration类
    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }

    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
        // 清除缓存
        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
    }
}