Spring ConfigurationClassPostProcessor详细解析

Scroll Down

ConfigurationClassPostProcessor概述

当XML配置文件中配置了< context:annotation-config/>或者< context:component-scan/>标签时,在解析这两个标签的过程中会注册一个ConfigurationClassPostProcessor。或者,我们当然也可以手动注册一个ConfigurationClassPostProcessor的bean定义,Spring Boot则自动帮我们注册了一个ConfigurationClassPostProcessor。
  在AnnotationConfigUtils的registerAnnotationConfigProcessors方法中(该方法在解析< context:annotation-config/>或者< context:component-scan/>标签时被调用),可以看到,如果此前没有手动注册名为CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME=“org.springframework.context.annotation.internalConfigurationAnnotationProcessor”的bean定义,那么以该字符串作为beanName注册一个ConfigurationClassPostProcessor类型的bean定义。

ConfigurationClassPostProcessor的uml类图:

image.png

可以看到,ConfigurationClassPostProcessor实现了BeanClassLoaderAware、ResourceLoaderAware、EnvironmentAware的这几个Aware感知接口,那么在创建该类实例的时候,将会回调这些接口的setter方法,将对应的参数设置进去。
  ConfigurationClassPostProcessor还是一个特殊的BeanDefinitionRegistryPostProcessor类型的后处理器,因此将会在容器初始化过程中的refresh方法中的invokeBeanFactoryPostProcessors方法中被实例化并且按顺序回调它的postProcessBeanDefinitionRegistry和postProcessBeanFactory方法,实际上这两个方法就是ConfigurationClassPostProcessor的工作入口,它们被Spring的回调机制自动调用。
  下面我们从ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry和postProcessBeanFactory方法入手来分析它的源码。

postProcessBeanDefinitionRegistry

  该方法在IoC容器初始化的invokeBeanFactoryPostProcessors步骤中被自动回调,在经过此前的obtainFreshBeanFactory方法之后,所有基于XML的bean定义(包括< context:component-scan/>等各种扩展标签引入的bean定义)已被加载,但是并没有加载完全,比如@Bean注解方法、非静态内部类的bean定义、@ComponentScan表示包、@Import引入bean等等……,这一步就是主要干这个事儿,从registry注册表中的已注册的配置类的bean定义中的内部类和其他的配置注解比如@Bean、@Conditional、@Import、@ComponentScan、@PropertySource一并解析,进一步提取 bean 定义并注册到注册表中。
  核心逻辑还是在内部的processConfigBeanDefinitions方法中完成的!

//---------ConfigurationClassPostProcessor的相关属性

/**
 * 被postProcessBeanDefinitionRegistry方法处理的registry的identityHashCode的缓存,用于防止重复处理
 */
private final Set<Integer> registriesPostProcessed = new HashSet<>();

/**
 * 被postProcessBeanFactory方法处理的registry的identityHashCode的缓存,用于防止重复处理
 */
private final Set<Integer> factoriesPostProcessed = new HashSet<>();

/**
 1. ConfigurationClassPostProcessor的方法
 2. <p>
 3. 主要功能就是从registry注册表中的已注册的配置类中进一步提取 bean 定义
 4.  5. @param registry bean定义注册表,实际类型就是当前上下文中的DefaultListableBeanFactory对象
 */
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    /*
     * 校验重复处理
     */
    //获取registry注册表的identityHashCode值作为registryId,实际上就是返回默认hashCode方法的返回值,无论有没有重写hashCode方法
    //一个registry对象有唯一的registryId值
    int registryId = System.identityHashCode(registry);
    //如果registriesPostProcessed缓存包含了该registryId值,那么说明此前该registry已被该ConfigurationClassPostProcessor处理过了
    //Spring不允许同一个ConfigurationClassPostProcessor重复处理同一个registry,直接抛出异常
    if (this.registriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
                "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
    }
    //如果factoriesPostProcessed缓存包含了该registryId值,那么说明此前该registry已被该ConfigurationClassPostProcessor处理过了
    //Spring不允许同一个ConfigurationClassPostProcessor重复处理同一个registry,直接抛出异常
    if (this.factoriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
                "postProcessBeanFactory already called on this post-processor against " + registry);
    }
    //当前registry的registryId加入registriesPostProcessed缓存
    this.registriesPostProcessed.add(registryId);
    /*
     * 继续调用processConfigBeanDefinitions方法,这是核心方法
     */
    processConfigBeanDefinitions(registry);
}

processConfigBeanDefinitions处理配置类bean定义

  该方法是处理配置类bean定义的核心方法,定义了大概骨架步骤:

  • 获取注册表中所有beanName数组,通过checkConfigurationClassCandidate方法判断依次判断是否是配置类并且设置属性,并封装为一个BeanDefinitionHolder加入configCandidates集合。
  • 如果configCandidates集合没有收集到任何配置类定义,那么直接返回,不需要进入下一步。
  • 对配置类根据@Order注解进行排序,按照排序顺序先后解析每一个的配置类定义,主要涉及到parse和loadBeanDefinitions这两个核心方法,也就是对配置类的各种注解的解析和bean定义的注册,逻辑很复杂,后面有源码详解。
  • 解析完毕之后,如果发现由于解析配置类而新增了bean定义,那么对这些新增的bean定义同样看作配置类,并且继续第三步循环处理,直到最后不再有新增的bean定义。
/**
 * ConfigurationClassUtils的属性
 * org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass属性名
 * 用于标记该配置类是否已被处理过了
 */
public static final String CONFIGURATION_CLASS_ATTRIBUTE =
        Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");

//-----------ConfigurationClassPostProcessor的相关属性-----------

/**
 * 是否有本地beanName生成器,默认false
 */
private boolean localBeanNameGeneratorSet = false;

/**
 * AnnotationBeanNameGenerator类型的beanName生成器
 * 默认作为@ComponentScan组件扫描注解的解析器componentScanParser 的beanName生成器
 */
private BeanNameGenerator componentScanBeanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;

/**
 * 用在注册配置类本身作为bean定义的时候,即被引入的bean的beanName生成器。
 * registerBeanDefinitionForImportedConfigurationClass方法中使用
 */
private BeanNameGenerator importBeanNameGenerator = IMPORT_BEAN_NAME_GENERATOR;

/**
 * FullyQualifiedAnnotationBeanNameGenerator类型的beanName生成器
 * 默认情况下,使用完全限定的类名作为默认的 bean 名称。
 */
public static final AnnotationBeanNameGenerator IMPORT_BEAN_NAME_GENERATOR =
        new FullyQualifiedAnnotationBeanNameGenerator();

/**
 * 环境变量,在创建该类实例时通过EnvironmentAware自动设置
 */
@Nullable
private Environment environment;

/**
 * 问题报告器,用于抛出异常
 */
private ProblemReporter problemReporter = new FailFastProblemReporter();

/**
 * 资源加载器,用于加载外部文件资源
 */
private ResourceLoader resourceLoader = new DefaultResourceLoader();

/**
 * 元数据读取器工厂
 */
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();

/**
 * bean定义加载器
 */
@Nullable
private ConfigurationClassBeanDefinitionReader reader;
/**
 * 手动注册的一个beanName
 */
private static final String IMPORT_REGISTRY_BEAN_NAME =
        ConfigurationClassPostProcessor.class.getName() + ".importRegistry";


/**
 * ConfigurationClassPostProcessor的方法
 * <p>
 * 主要功能就是从registry注册表中的已注册的配置类中进一步提取 bean 定义
 *
 * @param registry bean定义注册表,实际类型就是当前上下文中的DefaultListableBeanFactory对象
 */
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    //临时集合,用于存储配置类的bean定义
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    //返回此注册表中已注册的所有 bean 定义的名称数组
    String[] candidateNames = registry.getBeanDefinitionNames();
    /*
     * 1 遍历beanName数组,根据bean定义判断配置类,设置属性,并封装为一个BeanDefinitionHolder加入configCandidates集合
     */
    for (String beanName : candidateNames) {
        //根据beanName获取对应的bean定义
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        /*
         * 获取bean定义的"org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass"属性
         * bean定义的父类BeanMetadataAttributeAccessor的方法,如果不为null,说明当前Bean 定义已作为配置类处理过了,这里不再处理
         */
        if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
            if (logger.isDebugEnabled()) {
                logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
            }
        }
        /*
         * 否则,调用checkConfigurationClassCandidate校验当前bean定义是否对应着一个配置类,并为其设置相应的属性为lite或者full
         * 如果具有@Configuration注解以及派生注解,那么算作配置类,设置为full
         * 如果具有@Bean,@Component,@ComponentScan,@Import,@ImportResource注解及其派生注解之一,那么算作配置类,那么设置为lite
         * 后面会用到这个属性
         */
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            //如果是配置类,则封装成为一个BeanDefinitionHolder加入到configCandidates集合中
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }

    /*
     * 2 如果configCandidates集合没有收集到任何配置类定义,那么直接返回
     */
    if (configCandidates.isEmpty()) {
        return;
    }
    //到这一步,表示存在配置类

    /*
     * 3 将configCandidates集合中的配置类按照此前checkConfigurationClassCandidate解析的@Order注解的值排序,值越小越靠前
     */
    configCandidates.sort((bd1, bd2) -> {
        //获取order值进行比较
        //如果此前没有解析到@Order注解,那么将返回Ordered.LOWEST_PRECEDENCE,即Integer.MAX_VALUE,表示优先级最低,排在末尾
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });
    /*
     * 确定beanName生成器
     */
    SingletonBeanRegistry sbr = null;
    //DefaultListableBeanFactory属于SingletonBeanRegistry类型
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        //如果没有自定义的beanName生成器,可通过ConfigurationClassPostProcessor的setBeanNameGenerator方法设置,默认false
        if (!this.localBeanNameGeneratorSet) {
            //获取设置的beanName生成器,一般只有AnnotationConfigApplicationContext上下文的setBeanNameGenerator方法会设置
            //如果是其他上下文容器比如ClassPathXmlApplicationContext就是返回null
            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
                    AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
            //如果不为null
            if (generator != null) {
                //那么设置generator为将要使用的beanName生成器
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator;
            }
        }
    }
    //环境变量,在创建该类实例时通过EnvironmentAware自动设置
    if (this.environment == null) {
        this.environment = new StandardEnvironment();
    }
    /*
     * 4 解析每一个配置类定义
     */

    /*
     * 创建配置类解析器,传递:metadataReaderFactory - 元数据解析工厂、problemReporter -问题记录器
     * environment - 环境变量、resourceLoader - 资源加载器、registry - 注册表,就是当前DefaultListableBeanFactory对象
     * componentScanBeanNameGenerator - beanName生成器,默认就是AnnotationBeanNameGenerator
     */
    ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    //保存需要解析的配置类,默认保存configCandidates的中的全部配置类定义
    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    //保存已被解析的配置类
    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    do {
        /*
         * 通过parser解析器解析每一个配置类
         */
        parser.parse(candidates);
        /*
         * 通过parser解析器验证每一个配置类
         */
        parser.validate();

        //获取解析后的ConfigurationClass配置类集合
        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        //移除全部的alreadyParsed集合中的数据
        configClasses.removeAll(alreadyParsed);

        // Read the model and create bean definitions based on its content
        if (this.reader == null) {
            //创建配置类bean定义阅读器,用于创建BeanDefinition
            this.reader = new ConfigurationClassBeanDefinitionReader(
                    registry, this.sourceExtractor, this.resourceLoader, this.environment,
                    this.importBeanNameGenerator, parser.getImportRegistry());
        }
        /*
         * 通过reader加载、注册此configClasses中的bean定义,其来源包括
         * 包括配置类本身、@Bean方法、@ImportedResource注解、@Import注解
         */
        this.reader.loadBeanDefinitions(configClasses);
        //将configClasses存入已解析的集合中
        alreadyParsed.addAll(configClasses);
        //清空candidates集合
        candidates.clear();
        /*
         * 处理新增了bean定义的情况,将会循环解析新增的bean定义
         */
        //如果解析之后容器中已注册的bean定义数量大于在解析之前的bean定义数量,说明当前方法向注册表中注册了新的bean定义
        if (registry.getBeanDefinitionCount() > candidateNames.length) {
            //获取最新的bean定义名集合
            String[] newCandidateNames = registry.getBeanDefinitionNames();
            //oldCandidateNames保存一份candidateNames的副本
            Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
            //已解析的bean定义的className集合
            Set<String> alreadyParsedClasses = new HashSet<>();
            //将alreadyParsed中的全部configClass的className加入alreadyParsedClasses集合
            for (ConfigurationClass configurationClass : alreadyParsed) {
                alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
            }
            //遍历最新bean定义名集合
            for (String candidateName : newCandidateNames) {
                //如果当前遍历的候选beanName没在旧集合中,说明是新添加的
                if (!oldCandidateNames.contains(candidateName)) {
                    //获取当前candidateName的bean定义
                    BeanDefinition bd = registry.getBeanDefinition(candidateName);
                    //如果当前bean定义是配置类,并且没有被解析过
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                            !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                        //那么存入candidates集合中,此时candidates集合由有了数据,那么将回进行下一次循环,解析新添加的bean定义
                        candidates.add(new BeanDefinitionHolder(bd, candidateName));
                    }
                }
            }
            //candidateNames设置最新的newCandidateNames集合
            candidateNames = newCandidateNames;
        }
    }
    //如果candidates集合不为空,那么说明在本次解析过程中新添加了bean定义,继续循环解析这些新的bean定义
    while (!candidates.isEmpty());


    // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
    //如果注册表中不包含名为"org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry"的单例bean实例
    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        //那么手动注册一个单例bean实例,名为"org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry"
        //实际上就是importStack集合对象
        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }
    //默认就是CachingMetadataReaderFactory
    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
        //清除外部提供的元数据阅读器工厂MetadataReaderFactory中的缓存
        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
    }
}

getAttribute获取属性

  这里的“属性”并不是存储在BeanDefinition中的,而是存放在BeanDefinition实际类型的父类AttributeAccessorSupport的attributes缓存中的,该缓存属于对象级别,每一个bean定义都有自己的attributes缓存,因此不会共享。
  attributes默认是空集合,当调用下面的checkConfigurationClassCandidate方法时才会设置值,因此可用于判断当前bean定义是否已被解析过。

/**
 * BeanMetadataAttributeAccessor的方法
 * 获取属性,GenericBeanDefinition、ScannedGenericBeanDefinition等都属于BeanMetadataAttributeAccessor类型
 *
 * @param name 属性名
 * @return 属性值
 */
@Override
@Nullable
public Object getAttribute(String name) {
    //继续调用父类AttributeAccessorSupport的方法
    BeanMetadataAttribute attribute = (BeanMetadataAttribute) super.getAttribute(name);
    //如果没有就返回null,否则返回value值
    return (attribute != null ? attribute.getValue() : null);
}


/**
 * AttributeAccessorSupport的属性
 * <p>
 * 使用字符串键和对象值映射,这就是就是所谓的“属性”的缓存位置
 * 该缓存是存放在bean定义的父类AttributeAccessorSupport中的,默认是空集合
 */
private final Map<String, Object> attributes = new LinkedHashMap<>();

/**
 1. AttributeAccessorSupport的方法
 2. 获取属性
 3.  4. @param name 属性名
 5. @return 属性值
 */
@Override
@Nullable
public Object getAttribute(String name) {
    Assert.notNull(name, "Name must not be null");
    return this.attributes.get(name);
}

checkConfigurationClassCandidate判断配置类并设置属性

  如果获取到对应属性的值,那么说明当前bean定义没有被解析过,那么调用checkConfigurationClassCandidate解析判断当前bean定义表示的类是否是配置类。该方法位于ConfigurationClassUtils类中,这个类就是专门用于判断给定的bean定义是否是配置类的一个工具类。
  解析之后如果属于配置类那么会设置对应属性的值,后面会使用到,后续再进来的时候也不会再次解析。

  • 如果具有@Configuration注解及其派生注解标注并且proxyBeanMethods属性的值为true(默认就是true),那么算作配置类,设置属性 CONFIGURATION_CLASS_ATTRIBUTE = full,CONFIGURATION_CLASS_ATTRIBUTE就是“org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass”;
    proxyBeanMethods属性就表示是否需要代理@Bean方法,即对@Bean方法的调用实施bean生命周期行为,这将通过CGLIB子类拦截方法来完成。
  • 如果具有@Bean,@Component,@ComponentScan,@Import,@ImportResource注解及其派生注解之一,那么算作配置类,那么设置属性 CONFIGURATION_CLASS_ATTRIBUTE = lite;
  • 如果当前bean定义的类是一个配置类,并且具有@Order注解,那么会设置属性 ORDER_ATTRIBUTE = order值,ORDER_ATTRIBUTE就是“org.springframework.context.annotation.ConfigurationClassPostProcessor.order”;
  • 这里的属性是设置给当前bean定义实际类型(GenericBeanDefinition、ScannedGenericBeanDefinition等)的父类AttributeAccessorSupport的attributes缓存中的,key为name常量,value为根据name和value封装的一个BeanMetadataAttribute对象。
//-----------ConfigurationClassUtils的相关属性-------------

/**
 * 属性key
 * org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass
 */
public static final String CONFIGURATION_CLASS_ATTRIBUTE =
        Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");

/**
 * 属性key
 * org.springframework.context.annotation.ConfigurationClassPostProcessor.order
 * 如果当前bean定义的类是一个配置类,并且具有@Order注解,那么会设置属性 ORDER_ATTRIBUTE = order值
 */
private static final String ORDER_ATTRIBUTE =
        Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "order");

/**
 * 如果当前bean定义的类上具有@Configuration注解,或者以@Configuration注解为元注解的注解(派生注解)
 * 那么表示一个配置类,并且设置属性 CONFIGURATION_CLASS_ATTRIBUTE = full
 */
public static final String CONFIGURATION_CLASS_FULL = "full";
/**
 * 如果当前bean定义的类上具有@Bean,@Component,@ComponentScan,@Import,@ImportResource注解之一,或者以这些注解为元注解的注解(派生注解)
 * 那么表示一个配置类,并且设置属性 CONFIGURATION_CLASS_ATTRIBUTE = lite
 */
public static final String CONFIGURATION_CLASS_LITE = "lite";

/**
 * ConfigurationClassUtils的方法
 * <p>
 * 如果当前检查的类上没有@
 * 检查给定的 bean 定义是否是配置类并相应地标记它
 *
 * @param beanDef               要检查的bean定义
 * @param metadataReaderFactory 调用方正在使用的当前beanFactory工厂
 * @return 是否是配置类,true 是 false 否
 */
public static boolean checkConfigurationClassCandidate(
        BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
    //获取类型名,如果为null或者工厂方法名不为null,说明不是普通bean定义或者是工厂方法bean,返回false
    String className = beanDef.getBeanClassName();
    if (className == null || beanDef.getFactoryMethodName() != null) {
        return false;
    }
    AnnotationMetadata metadata;
    //如果是支持注解类型的bean定义,如果是采用组件注解添加的bean定义那么支持,并且元数据来自同一个类
    if (beanDef instanceof AnnotatedBeanDefinition &&
            className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
        //获取类元数据
        metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
    }
    /*
     * 如果是普通类型的bean定义,也就是通过XML配置添加的bean定义
     */
    else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
        // Check already loaded Class if present...
        // since we possibly can't even load the class file for this Class.
        //获取所属类型
        Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
        //如果类型属于BeanFactoryPostProcessor,或者属于BeanPostProcessor,或者属于AopInfrastructureBean,或者属于EventListenerFactory
        //那么返回false,表示不是配置类
        if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
                BeanPostProcessor.class.isAssignableFrom(beanClass) ||
                AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
                EventListenerFactory.class.isAssignableFrom(beanClass)) {
            return false;
        }
        //获取类元数据
        metadata = AnnotationMetadata.introspect(beanClass);
    }
    /*
     * 否则
     */
    else {
        try {
            //直接获取元数据
            MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
            metadata = metadataReader.getAnnotationMetadata();
        } catch (IOException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Could not find class file for introspecting configuration annotations: " +
                        className, ex);
            }
            return false;
        }
    }
    /*
     * 解析类元数据,判断是否是配置类
     */

    //获取该类上的@Configuration注解的属性映射map,包括以@Configuration注解为元注解的注解
    Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
    /*
     * 如果config不为null,表示存在@Configuration注解获取以@Configuration注解为元注解的注解
     * 并且proxyBeanMethods属性的值为true,默认就是true
     */
    if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
        //那么设置当前bean定义的属性,bean定义的父类BeanMetadataAttributeAccessor的方法
        //org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass = full
        beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
    }
    /*
     * 否则,如果是其他配置类
     * */
    else if (config != null || isConfigurationCandidate(metadata)) {
        //那么设置当前bean定义的属性,bean定义的父类BeanMetadataAttributeAccessor的方法
        //org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass = lite
        beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
    }
    /*
     * 否则,表示不是配置类,返回false
     */
    else {
        return false;
    }
    //到这里,表示属于配置类
    //确定给定配置类元数据的顺序
    //获取当前bean定义的@Order注解的值
    Integer order = getOrder(metadata);
    //如果设置了order值
    if (order != null) {
        //那么设置当前bean定义的属性,bean定义的父类BeanMetadataAttributeAccessor的方法
        //org.springframework.context.annotation.ConfigurationClassPostProcessor.order = order值
        beanDef.setAttribute(ORDER_ATTRIBUTE, order);
    }
    //返回true
    return true;
}

isConfigurationCandidate是否是配置类

  如果当前bean定义所属的类没有@Configuration注解以及派生注解,那么继续调用isConfigurationCandidate方法检查:如果类上存在@Component、@ComponentScan、@Import、@ImportResource注解及其派生注解,或者至少有一个方法上具有@Bean注解,那么同样算作配置类。

/**
 * 配置类的候选者,ConfigurationClassUtils加载的时候就填充了数据
 * 如果某个类具有内部的任意一个注解或者派生注解,那么就算作配置类
 */
private static final Set<String> candidateIndicators = new HashSet<>(8);

/*
 * 静态块
 */
static {
    //加入@Component、@ComponentScan、@Import、@ImportResource注解类名
    candidateIndicators.add(Component.class.getName());
    candidateIndicators.add(ComponentScan.class.getName());
    candidateIndicators.add(Import.class.getName());
    candidateIndicators.add(ImportResource.class.getName());
}

/**
 * 确定是否是配置类
 *
 * @param metadata 类的元数据
 * @return true 是 false 否
 */
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
    // 如果是接口,那么不考虑
    if (metadata.isInterface()) {
        return false;
    }

    /*
     * 遍历candidateIndicators集合,如果当前类具有@Component、@ComponentScan、@Import、@ImportResource注解及其派生注解的任何一个
     * 那么算作配置类
     */
    for (String indicator : candidateIndicators) {
        if (metadata.isAnnotated(indicator)) {
            return true;
        }
    }
    //上面的循环没确定结果,那么继续查找@Bean注解标注的方法
    try {
        //如果该类的存在至少一个具有@Bean注解及其派生注解标注的方法,那么算作配置类
        return metadata.hasAnnotatedMethods(Bean.class.getName());
    } catch (Throwable ex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
        }
        return false;
    }
}

getOrder获取@Order注解值

  getOrder用于获取当前bean定义所属的类上的@Order注解的值,如果存在该注解,那么后续还会添加一个ORDER_ATTRIBUTE属性到当前bean定义中。

/**
 * 获取@Order注解的值,用于确定给定配置类元数据的顺序
 *
 * @param metadata 类元数据
 * @return 配置类的@Order注解的值,如果没有@Order注解,那么返回null
 */
@Nullable
public static Integer getOrder(AnnotationMetadata metadata) {
    Map<String, Object> orderAttributes = metadata.getAnnotationAttributes(Order.class.getName());
    return (orderAttributes != null ? ((Integer) orderAttributes.get(AnnotationUtils.VALUE)) : null);
}

setAttribute设置属性

  如果当前bean定义所属的类是配置类,那么设置key为CONFIGURATION_CLASS_ATTRIBUTE的属性,也就是“org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass”,value就是“full”或者“lite”值。
  如果当前bean定义所属的类是配置类并且具有@Order注解,那么设置key为ORDER_ATTRIBUTE的属性,也就是“org.springframework.context.annotation.ConfigurationClassPostProcessor.order”,value就是order值。
  实际存入缓存的值是key和value封装的一个BeanMetadataAttribute对象。

/**
 * BeanMetadataAttributeAccessor的方法
 * 设置属性,GenericBeanDefinition、ScannedGenericBeanDefinition等都属于BeanMetadataAttributeAccessor类型
 *
 * @param name  属性名
 * @param value 属性值
 */
@Override
public void setAttribute(String name, @Nullable Object value) {
    //调用父类BeanMetadataAttributeAccessor的方法
    //key为name,value为根据name和value封装的一个BeanMetadataAttribute对象
    super.setAttribute(name, new BeanMetadataAttribute(name, value));
}


/**
 * AttributeAccessorSupport的属性
 * <p>
 * 使用字符串键和对象值映射,这就是就是属性的缓存位置
 */
private final Map<String, Object> attributes = new LinkedHashMap<>();

/**
 * AttributeAccessorSupport的方法
 * 设置属性到缓存中
 *
 * @param name  属性名
 * @param value 属性值
 */
@Override
public void setAttribute(String name, @Nullable Object value) {
    Assert.notNull(name, "Name must not be null");
    if (value != null) {
        this.attributes.put(name, value);
    } else {
        removeAttribute(name);
    }
}

getOrder获取顺序值

  获取配置类的order顺序值,也就是配置类上的@Order注解的值,如果未声明则返回Ordered.LOWEST_PRECEDENCE,即Integer.MAX_VALUE,将会排序在集合尾部。

/**
 * ConfigurationClassUtils的属性
 * 表示具有@Order注解的属性的key
 */
private static final String ORDER_ATTRIBUTE =
        Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "order");


/**
 * ConfigurationClassUtils的方法
 * 获取配置类的order顺序值,也就是
 * 配置类上的@Order注解的值,如果未声明则返回Ordered.LOWEST_PRECEDENCE,即Integer.MAX_VALUE
 *
 * @param beanDef 要检查的bean定义
 * @return 配置类的order顺序值
 */
public static int getOrder(BeanDefinition beanDef) {
    //获取ORDER_ATTRIBUTE属性值order,这个属性我们在checkConfigurationClassCandidate方法中已尝试解析并设置到属性中了
    //这里直接取出来使用,如果没有@Order注解会返回null
    Integer order = (Integer) beanDef.getAttribute(ORDER_ATTRIBUTE);
    //如果order不为null,那么直接返回,否则返回Ordered.LOWEST_PRECEDENCE,即Integer.MAX_VALUE
    return (order != null ? order : Ordered.LOWEST_PRECEDENCE);
}

new ConfigurationClassParser创建解析器

  创建一个ConfigurationClassParser解析器对象,专门用于解析找到的配置类定义。初始化一些属性。

//----------ConfigurationClassParser相关属性-------------

private final MetadataReaderFactory metadataReaderFactory;

private final ProblemReporter problemReporter;

private final Environment environment;

private final ResourceLoader resourceLoader;

private final BeanDefinitionRegistry registry;

private final ComponentScanAnnotationParser componentScanParser;

private final ConditionEvaluator conditionEvaluator;

/**
 * 创建一个ConfigurationClassParser实例,用于解析配置类集合。
 *
 * @param metadataReaderFactory          元数据解析工厂
 * @param problemReporter                问题报告器
 * @param environment                    环境变量
 * @param resourceLoader                 资源加载器
 * @param componentScanBeanNameGenerator beanName生成器,默认就是AnnotationBeanNameGenerator
 * @param registry                       注册表,就是当前DefaultListableBeanFactory对象
 */
public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
                                ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
                                BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) {
    //为一些属性赋值
    this.metadataReaderFactory = metadataReaderFactory;
    this.problemReporter = problemReporter;
    this.environment = environment;
    this.resourceLoader = resourceLoader;
    this.registry = registry;
    //@ComponentScan组件扫描注解的解析器
    this.componentScanParser = new ComponentScanAnnotationParser(
            environment, resourceLoader, componentScanBeanNameGenerator, registry);
    //@Conditional条件注解评估器
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}

parser.parse解析配置类

  通过ConfigurationClassParser解析器去解析所有的配置类定义。其内部是循环调用processConfigurationClass方法按照此前排序的先后顺序处理每一个配置类,传递的参数是一个ConfigurationClass对象和一个排除类型过滤器。ConfigurationClass表示一个配置类,保存了配置类的相关信息。

/**
 * ConfigurationClassParser的方法
 * <p>
 * 解析配置类的bean定义集合,实际上也就是AnnotationConfigApplicationContext容器的构造器参数个数
 *
 * @param configCandidates 配置类的bean定义集合
 */
public void parse(Set<BeanDefinitionHolder> configCandidates) {
    //遍历集合
    for (BeanDefinitionHolder holder : configCandidates) {
        //获取bean定义
        BeanDefinition bd = holder.getBeanDefinition();
        //根据类型调用不同的parse方法,其内部都是调用的processConfigurationClass方法
        try {
            //如果属于AnnotatedBeanDefinition,比如AnnotatedGenericBeanDefinition、ScannedGenericBeanDefinition、ConfigurationClassBeanDefinition
            if (bd instanceof AnnotatedBeanDefinition) {
                //调用另一个parse方法解析,内部调用processConfigurationClass方法
                parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
            }
            //否则,如果是AbstractBeanDefinition类型,比如GenericBeanDefinition,并且已经解析了class
            else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                //调用另一个parse方法解析,内部调用processConfigurationClass方法
                parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
            }
            //否则
            else {
                //调用另一个parse方法解析,内部调用processConfigurationClass方法
                parse(bd.getBeanClassName(), holder.getBeanName());
            }
        } catch (BeanDefinitionStoreException ex) {
            throw ex;
        } catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                    "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
        }
    }
    //最后处理在processImports方法解析@Import注解时遇到的DeferredImportSelector,内部同样是调用processImports方法继续递归处理
    this.deferredImportSelectorHandler.process();
}
/*
 * 三个parse方法内部都是调用的processConfigurationClass方法,传递的参数是一个ConfigurationClass对象
 * 和一个排除类型过滤器,ConfigurationClass表示一个配置类,保存了配置类的相关信息
 */

/**
 * ConfigurationClassParser的属性
 * <p>
 * 类型排除过滤器,这是一个i嗯lambda对象
 * 如果类名以"java.lang.annotation."或者"org.springframework.stereotype."开头,就返回true,或者返回false
 */
private static final Predicate<String> DEFAULT_EXCLUSION_FILTER = className ->
        (className.startsWith("java.lang.annotation.") || className.startsWith("org.springframework.stereotype."));


protected final void parse(@Nullable String className, String beanName) throws IOException {
    Assert.notNull(className, "No bean class name for configuration class bean definition");
    MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
    processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
}

protected final void parse(Class<?> clazz, String beanName) throws IOException {
    processConfigurationClass(new ConfigurationClass(clazz, beanName), DEFAULT_EXCLUSION_FILTER);
}

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}

processConfigurationClass处理一个配置类

首先通过shouldSkip判断是否有必要继续解析这个配置类,参数设置的配置生效的阶段为ConfigurationPhase.PARSE_CONFIGURATION,即类的阶段。这是对于@Conditional注解的支持。这个方法我们在此前的IoC容器初始化的doScan扫描包阶段的isCandidateComponent方法中就见过了。
随后处理被Import引入的配置类的情况;
最后调用doProcessConfigurationClass核心方法,真正的去解析该配置类及其父类。

//------------ConfigurationClassParser的相关属性-----------

/**
 * 解析@Conditional条件注解的评估器
 * Spring 4.0 新增的@Conditional条件注解,可以标注在类或者方法上,在容器启动时用于控制一批或者一个bean实例是否被注入
 * 通过判断该注解中指定的条件是否满足,如果不满足则不会将对应的bean注入到容器中,如果满足则会将对应的bean进行注入
 */
private final ConditionEvaluator conditionEvaluator;

/**
 * 已解析的配置类缓存map
 */
private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();

/**
 * 已知的超类配置类缓存map
 */
private final Map<String, ConfigurationClass> knownSuperclasses = new HashMap<>();

/**
 * ConfigurationClassParser的方法
 * <p>
 * 处理每一个配置类
 *
 * @param configClass 表示配置类的对象,包含配置类的一些信息
 * @param filter      类型过滤器
 */
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
    /*
     * 1 通过判断类上的@Conditional条件注解是否满足Condition条件来控制是否跳过该配置类的解析
     * 参数设置的配置生效的阶段为ConfigurationPhase.PARSE_CONFIGURATION,即类的阶段
     */
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }
    /*
     * 2 处理被@Import引入的bean定义的情况
     */

    //将当前configClass作为key,尝试获取configClass集合中的configClass的缓存
    //ConfigurationClass的hashCode和equals方法都被重写了,比较的是内部的className字符串的hashCode
    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    //如果existingClass不为null,说明此前该类已被@Import引入
    if (existingClass != null) {
        //如果当前configClass的importedBy属性集合不为空,说明当前bean定义是被@Import引入的
        if (configClass.isImported()) {
            //如果此前的existingClass的importedBy属性集合也不为空,说明此前同类型的bean定义也是被@Import引入的
            if (existingClass.isImported()) {
                //对引入该配置类的引入类进行合并,也就是将当前@Import所在的引入类添加到内部的importedBy属性集合中
                existingClass.mergeImportedBy(configClass);
            }
            //随后直接返回,即对于同一个被@Import引入的类在configurationClasses集合中只存一个
            // Otherwise ignore new imported config class; existing non-imported class overrides it.
            return;
        }
        //否则,表示当前的bean定义不是被@Import引入的,那么表示属于显示注入的,比如通过组件注解
        //因此需要覆盖此前保存的通过@Import引入的bean定义
        else {
            // Explicit bean definition found, probably replacing an import.
            // Let's remove the old one and go with the new one.
            //移除configurationClasses中之前的configClass
            this.configurationClasses.remove(configClass);
            //移除configurationClasses中之前的configClass
            this.knownSuperclasses.values().removeIf(configClass::equals);
        }
    }

    /*
     * 3 递归处理配置类及其超类
     */

    //获取当前配置类的SourceClass,这是一个简单的包装器,允许以统一的方式处理带注释的源类,而不管它们如何加载。
    SourceClass sourceClass = asSourceClass(configClass, filter);
    do {
        /*
         * 核心方法,处理每一个配置类及其超类
         */
        sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
    }
    while (sourceClass != null);
    //当前的configClass存入configurationClasses集合,key和value都是同一个对象
    this.configurationClasses.put(configClass, configClass);
}

shouldSkip解析@Conditional判断是否跳过

  通过判断class上的@Conditional条件注解是否满足Condition条件来控制是否跳过该配置类的解析。在这里,设置的配置生效的阶段参数为ConfigurationPhase.PARSE_CONFIGURATION,即解析配置类的阶段,如果此时某个Condition是REGISTER_BEAN阶段,那么该Condition无论有没有满足条件都不生效(都算作满足)。
  这里是对@Conditional条件注解的支持,Spring 4.0 新增的@Conditional条件注解,可以标注在类或者方法上,在容器启动时用于控制一批或者一个bean实例是否被注入,通过判断该注解中指定的条件是否满足,如果不满足则不会将对应的bean注入到容器中,如果满足则会将对应的bean进行注入或者进一步处理。

/**
 1. ConditionEvaluator的方法
 2. <p>
 3. 确定是否应基于@Conditional注解跳过此项(类或者方法的解析)
 4. <p>
 5. Spring 4.0 新增的@Conditional条件注解,可以标注在类或者方法上,在容器启动时用于控制一批或者一个bean实例是否被注入
 6. 通过判断该注解中指定的条件是否满足,如果不满足则不会将对应的bean注入到容器中,如果满足则会将对应的bean进行注入
 7.  8. @param metadata 类或者方法元数据
 9. @param phase    配置生效的阶段
 10.                 ConfigurationPhase.PARSE_CONFIGURATION   解析配置类的阶段
 11.                 ConfigurationPhase.REGISTER_BEAN   解析配置类的方法阶段
 12. @return 如果此项应跳过,则返回true,否则返回false
 */
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
    //如果元数据所属的类或者方法(根据元数据的类型)上没有@Conditional注解,那么直接返回false
    if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
        return false;
    }
    /*
     * 如果配置生效的阶段为null,那么根据元数据类型自动选择一个阶段重新调用shouldSkip方法
     * 在前面讲的IoC容器初始化的扫描包阶段的isCandidateComponent方法中就调用了这个方法,并且phase参数传递的null
     */
    if (phase == null) {
        //如果是AnnotationMetadata类型,表示当前元数据是类元数据,比如SimpleAnnotationMetadata,那么phase设置为PARSE_CONFIGURATION
        if (metadata instanceof AnnotationMetadata &&
                ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
            return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
        }
        //否则,表示当前元数据是方法元数据,比如MethodMetadata,那么phase设置为REGISTER_BEAN
        return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
    }
    /*
     * 提取@Conditional注解中配置的全部Condition条件
     */
    List<Condition> conditions = new ArrayList<>();
    for (String[] conditionClasses : getConditionClasses(metadata)) {
        for (String conditionClass : conditionClasses) {
            Condition condition = getCondition(conditionClass, this.context.getClassLoader());
            conditions.add(condition);
        }
    }
    /*
     * 对全部Condition条件进行排序,可以看到采用的是AnnotationAwareOrderComparator比较器
     * 该比较器支持Ordered、PriorityOrdered接口,以及@Order、@Priority注解的排序
     * 排序规则是order值越小排序越靠前,优先级越高
     */
    AnnotationAwareOrderComparator.sort(conditions);

    for (Condition condition : conditions) {
        //必须的配置生效的阶段,只有ConfigurationCondition类型的条件才具备该属性
        ConfigurationPhase requiredPhase = null;
        if (condition instanceof ConfigurationCondition) {
            //获取配置生效的阶段
            requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
        }
        //如果配置生效的阶段为null或者与参数的阶段相同,并且当前Condition的条件不满足,那么返回true,表示可以跳过此项目
        if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
            return true;
        }
    }
    //所有Condition都满足,那么返回false,表示不跳过
    return false;
}

@Conditional注解介绍

  Spring 4.0 新增的@Conditional条件注解,可以标注在类或者方法上,在容器启动时用于控制一批或者一个bean实例是否被注入,通过判断该注解中指定的条件是否满足,如果不满足则不会将对应的bean注入到容器中,如果满足则会将对应的bean进行注入或者进一步处理。

  • 标注在类上时,如果它内部的Condition条件不满足,那么该类的bean定义以及该类下面的bean定义,比如通过@Bean注解指定的方法表示的bean定义都不会被解析注册。
  • 标注在方法上时,如果它内部的Condition条件不满足,那么该方法表示的bean定义(通过@Bean注解)不会被解析注册。
      
    @Conditional的参数是一个类型的数组,类型必须是属于Condition接口体系,这个Condition接口有一个matches方法,该方法返回一个boolean值,返回true表示该匹配条件,返回false则表示不匹配。只有所有的Conditon条件都匹配才算做最终满足条件。该方法的ConditionContext条件变量可以获取各种容器参数,比如Registry、BeanFactory、Environment、ResourceLoader、ClassLoader。
@FunctionalInterface
public interface Condition {
    /**
     * 确定条件是否匹配
     *
     * @param context  条件上下文,可以从李米娜获取这种各样的内部参数
     * @param metadata 被检查的类或者方法的元数据
     * @return 条件匹配返回true,条件不匹配返回false
     */
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

Condition还有一个特性化子接口ConfigurationCondition。这个接口多了一个getConfigurationPhase方法,用于指定该Conditon的生效阶段,可选类型保存在这个接口内部的ConfigurationPhase枚举中。该接口用的比较少。
  如果某个条件是ConfigurationCondition类型,那么先判断阶段是否匹配,如果匹配,再判断条件是否匹配,如果阶段不匹配,那么该条件不生效,即默认条件匹配。这一点看上面的源码就能看出来。

public interface ConfigurationCondition extends Condition {

    /**
     * 返回该条件的配置生效阶段
     */
    ConfigurationPhase getConfigurationPhase();

    /**
     * 配置的阶段枚举
     */
    enum ConfigurationPhase {

        /**
         * 解析配置类的阶段
         */
        PARSE_CONFIGURATION,

        /**
         * 注册Bean的阶段
         */
        REGISTER_BEAN
    }
}

@Conditional注解使用

  我们自定义两个Condition:

/**
 * @author lx
 * @date 2020/11/5 16:16
 */
public class MyConditional {

    /**
     * 用于排序的@Priority注解
     */
    @Priority(2)
    public static class MyConditional1 implements Condition {

        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Environment environment = context.getEnvironment();
            //如果设置了key为"p"的环境变量,那么该条件满足,否则不满足
            return environment.getProperty("p") != null;
        }

    }

    @Priority(1)
    public static class MyConditional2 implements Condition {

        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

            return true;
        }
    }
}

定义一个测试类com.spring.source.conditional.ConditionTest,加上@Conditional注解,包含两个条件:

/**
 * @author lx
 * @date 2020/11/5 16:16
 */
@Component
@Conditional({MyConditional.MyConditional1.class, MyConditional.MyConditional2.class})
public class ConditionTest { }

配置文件spring-config-conditional.xml:

<context:component-scan base-package="com.spring.source.conditional"/>

测试:

@Test
public void conditional() {
    //设置环境变量
    System.setProperty("p", "x");
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring-config-conditional.xml");
    System.out.println(ac.getBean("conditionTest"));
}

由于设置了p环境变量,因此满足条件,所以该bean顶以被注册,能够获取到对应的实例,结果如下:

com.spring.source.conditional.ConditionTest@1198b989

如果我们将设置环境变量的代码注释掉,继续测试,将会抛出异常:

No bean named 'conditionTest' available

即,由于条件不满足,造成该bean定义被没有注册和初始化,因此获取不到对应的实例。

doProcessConfigurationClass处理一个配置类

  这是对一个配置类的真正的处理方法。将会对配置类的内部类、超类、以及相关注解进行处理,大概步骤为:

  • 处理内部类:
    如果当前配置类上存在@Component以及派生注解,包括@Repository、@Service、@Controller、@Configuration等注解,那么调用processMemberClasses方法首先处理内部类配置类。
    如果内部类也是一个配置类,那么将会递归调用processConfigurationClass方法先解析内部配置类。非静态内部类的bean定义的注册就是从该方法开始的(因为在doScan扫描包的方法中不会解析、注册非静态内部类的bean定义)。
  • 处理@PropertySources、@PropertySource注解:
    如果当前配置类上存在@PropertySources或者@PropertySource以及它们的派生注解,那么调用processPropertySource解析这些注解。@PropertySources、@PropertySource用于引入本地本地properties属性源文件,可用来替代XML的配置,比如< context:property-placeholder/>标签。@PropertySources、@PropertySource注解可重复出现。
    这里的properties属性源文件路径支出占位符,将会environment环境变量中查找,而解析出来的本地属性源同样会存入environment环境变量中。
  • 处理@ComponentScans、@ComponentScan注解:
    @ComponentScans、@ComponentScan注解用于配置组件扫描,可用来替代XML的配置,比如< context:component-scan/>标签。
    如果shouldSkip方法返回false,即不应该跳过,这里的phase生效的阶段参数为REGISTER_BEAN,那么调用componentScanParser.parse方法解析配置类上的@ComponentScan注解、扫描bean定义并进行注册,否则跳过解析。
    该注解配置的包路径的最终同样是依靠ClassPathBeanDefinitionScanner的doScan方法进行扫描的,因此和此前< context:component-scan/>的注解解析可以说是殊途同归。
  • 处理@Import注解:
    @Import注解可用于引入一批指定类型的bean定义,这是另一种注册bean定义的方式;通过processImports方法处理配置类上的@Import注解。
    而@Import注解也有三种添加bean定义的方法:普通类型、ImportSelector类型、ImportBeanDefinitionRegistrar类型。注意通过@Import引入的bean定义在这里并不会被注册
  • 处理@ImportResource注解:
    @ImportResource注解可用于引入一批Spring的XML配置文件,如果即基于注解开发又写了XML配置文件,那么可以使用该注解引入Spring的XML配置文件。
    这里仅仅对于@ImportResource注解引入的配置文件路径进行占位符的替换(从environment环境变量中查找),并方法替换后的路径和reader读取器通过addImportedResource方法存入configClass的importedResources缓存中,后续再继续处理。
  • 处理@Bean注解:
    处理配置类内部的@Bean注解标注的方法,@Bean注解用于通过方法引入bean定义,类似于工厂方法。
    这里同样是仅仅将解析后的方法元数据通过addBeanMethod方法存入configClass的beanMethods缓存中,后续再继续处理。
  • 处理接口上的默认方法:
    默认方法是Java8的新特性,主要就是对接口上标注了@Bean注解的默认方法进行类似于上一步的处理,存入configClass的beanMethods缓存中,后续再处理。
  • 处理父类:
    置类的父类将会被同样解析,配置类的父类将会被同样解析,而对于以"java."类路径开头的父类,比如Object,也就是rt.jar包中的Java核心类作为父类时不会被解析。
    如果存在非核心父类,那么返回父类的sourceClass,将会在外层的processConfigurationClass中进行下一次循环解析父类。
    如果没有符合规则的父类或者都解析完毕,那么返回null,将会在外层的processConfigurationClass中跳出循环,进行后续步骤。
      该方法对于通过@ComponentScans、@ComponentScan注解引入的bean定义会添加到了容器中,但是对于@Import、@Bean、@ImportResource注解引入的bean定义并没有注册到容器中,而是在后面的this.reader.loadBeanDefinitions()方法中才会真正的解析和注册。
//--------------ConfigurationClassParser的相关属性
/**
 * 解析@Conditional条件注解的评估器
 * Spring 4.0 新增的@Conditional条件注解,可以标注在类或者方法上,在容器启动时用于控制一批或者一个bean实例是否被注入
 * 通过判断该注解中指定的条件是否满足,如果不满足则不会将对应的bean注入到容器中,如果满足则会将对应的bean进行注入
 */
private final ConditionEvaluator conditionEvaluator;

/**
 * 解析@ComponentScan注解的解析器,在ConfigurationClassParser对象的构造器中被初始化
 */
private final ComponentScanAnnotationParser componentScanParser;

/**
 * ConfigurationClassParser的方法
 * <p>
 * 通过从sourceClass读取注解、成员和方法,应用处理并构建完整的ConfigurationClass。当发现多个相关sourceClass时,可以多次调用此方法。
 *
 * @param configClass 表示当前配置类的对象
 * @param sourceClass 源类
 * @param filter      类型过滤器
 * @return 超类的sourceClass,如果未找到或以前处理过就返回null
 */
@Nullable
protected final SourceClass doProcessConfigurationClass(
        ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
        throws IOException {
    /*
     * 1 处理内部类
     * 如果元数据所属的类上存在@Component以及派生注解,那么调用processMemberClasses方法首先处理内部类配置类
     * 常见包括@Component、@Repository、@Service、@Controller、@Configuration等注解
     */
    if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
        /*
         * 递归处理任何成员(嵌套)类,也就是内部类。内部配置类最终还是会调用processConfigurationClass方法
         */
        processMemberClasses(configClass, sourceClass, filter);
    }

    /*
     * 2 处理@PropertySources、@PropertySource注解
     * 如果元数据所属的类上存在@PropertySources或者@PropertySource以及它们的派生注解,那么调用processPropertySource解析这些注解
     * @PropertySources、@PropertySource用于引入本地properties属性源文件,可用来替代XML的配置,比如<context:property-placeholder/>标签
     * @PropertySources、@PropertySource注解可重复出现
     */

    /*
     * 调用attributesForRepeatable方法获取元数据所属的类上的全部@PropertySources、@PropertySource注解的属性集合AnnotationAttributes的集合
     * 遍历获取到的全部AnnotationAttributes属性集合
     */
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), PropertySources.class,
            org.springframework.context.annotation.PropertySource.class)) {
        if (this.environment instanceof ConfigurableEnvironment) {
            /*
             * 调用processPropertySource处理通过@PropertySource注解引入的属性源,会将引入的属性源加入到environment环境变量中
             */
            processPropertySource(propertySource);
        } else {
            logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                    "]. Reason: Environment must implement ConfigurableEnvironment");
        }
    }

    /*
     * 3 处理@ComponentScans、@ComponentScan注解
     * @ComponentScans、@ComponentScan注解用于组件扫描,可用来替代XML的配置,比如<context:component-scan/>标签
     */

    /*
     * 调用attributesForRepeatable方法获取元数据所属的类上的全部@ComponentScans、@ComponentScan注解的属性集合AnnotationAttributes的集合
     */
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    //如果存在@ComponentScan注解,并且shouldSkip方法返回false,即不应该跳过,这里的phase生效的阶段参数为REGISTER_BEAN,即注册bean的阶段
    //这两个条件都满足,那么可以解析继续@ComponentScan注解,进而继续扫描包,注册bean定义
    if (!componentScans.isEmpty() &&
            !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
        //遍历componentScans集合
        for (AnnotationAttributes componentScan : componentScans) {
            // The config class is annotated with @ComponentScan -> perform the scan immediately
            /*
             * 通过解析器解析@ComponentScan注解,获取解析到的bean定义集合
             */
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            // 检查扫描到的bean定义集合,以查找任何的配置类,并根据需要递归的解析
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();
                }
                //调用checkConfigurationClassCandidate判断是否是配置类并设置属性
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    /*
                     * 如果扫描到的bean定义是配置类,那么调用parse方法解析配置类,内部还是递归调用的processConfigurationClass方法
                     */
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }
    /*
     * 4 处理@Import注解
     * @Import注解可用于引入一批指定类型的bean定义
     */
    // Process any @Import annotations
    processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

    /*
     * 5 处理@ImportResource注解
     * @ImportResource注解可用于引入一批Spring的XML配置文件,如果即基于注解开发又写了XML配置文件,那么可以使用该注解引入Spring的XML配置文件
     */

    /*
     * 调用attributesFor方法获取元数据所属的类上的@ImportResource注解的属性集合AnnotationAttributes
     */
    AnnotationAttributes importResource =
            AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
    //如果不为null,说明存在@ImportResource注解
    if (importResource != null) {
        //获取locations属性数组,就是XML配置文件的路径字符串
        String[] resources = importResource.getStringArray("locations");
        //获取reader属性,用来读取配置文件中的bean定义
        Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
        //遍历配置文件路径
        for (String resource : resources) {
            //使用environment环境变量解析路径字符串的占位符
            String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
            /*
             * 仅仅是存入configClass的importedResources缓存中,后续再处理
             */
            configClass.addImportedResource(resolvedResource, readerClass);
        }
    }
    /*
     * 6 处理配置类内部的@Bean注解标注的方法
     * @Bean注解用于通过方法引入bean定义,类似于工厂方法
     */

    // Process individual @Bean methods
    //获取所有被@Bean注解标注的方法的元数据集合
    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    for (MethodMetadata methodMetadata : beanMethods) {
        /*
         * 仅仅是存入configClass的beanMethods缓存中,后续再处理
         */
        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }

    /*
     * 7 处理接口上的默认方法,Java8的新特性
     * 主要就是对接口上标注了@bean注解的默认方法进行类似于上一步的处理,存入configClass的beanMethods缓存中,后续再处理
     */
    // Process default methods on interfaces
    processInterfaces(configClass, sourceClass);

    /*
     * 8 处理父类
     * 配置类的父类将会被同样解析,而对于以"java."类路径开头的父类,比如Object,也就是rt.jar包中的Java核心类作为父类时不会被解析
     */
    // Process superclass, if any
    if (sourceClass.getMetadata().hasSuperClass()) {
        String superclass = sourceClass.getMetadata().getSuperClassName();
        if (superclass != null && !superclass.startsWith("java") &&
                !this.knownSuperclasses.containsKey(superclass)) {
            this.knownSuperclasses.put(superclass, configClass);
            // Superclass found, return its annotation metadata and recurse
            //返回父类的sourceClass,将会在外层的processConfigurationClass中进行下一次循环解析父类。
            return sourceClass.getSuperClass();
        }
    }

    // No superclass -> processing is complete
    /*
     * 10 如果没有符合规则的父类或者都解析完毕,那么返回null,将会在外层的processConfigurationClass中跳出循环,进行后续步骤。
     */
    return null;
}

//----------ConfigurationClass的相关属性-------------

/**
 * 通过@ImportResource注解引入的配置文件路径字符串到reader解析器的映射
 */
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
        new LinkedHashMap<>();
/**
 * 所有被@Bean注解标注的方法的元数据集合
 */
private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();

/**
 * 通过@ImportResource注解解析出来的配置文件路径存入configClass的importedResources缓存中
 */
public void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
    this.importedResources.put(importedResource, readerClass);
}

/**
 * 被@Bean注解标注的方法元数据存入beanMethods集合
 */
public void addBeanMethod(BeanMethod method) {
    this.beanMethods.add(method);
}

processMemberClasses处理内部类配置类

  doProcessConfigurationClass方法的第一步就是尝试调用processMemberClasses来处理当前配置类的内部类,如果内部类是一个配置类,那么首先解析内部配置类,最终内部类也会调用processConfigurationClass方法递归解析,并且外部配置类会被设置到内部配置类的importedBy集合中,表示内部类算作被外部类import引入进来的。
  还记得我们之前在IoC容器初始化的时候,讲的扩展标签解析的doScan方法内的第二个isCandidateComponent方法吗,该方法将非静态内部类都排除了,因此,非静态内部类的bean定义还没有注册到容器中,但是我们却能取到对应的bean实例,那么它是在哪里解析的呢?就是在这里,processMemberClasses方法就是真正的解析、注册非静态内部类的bean定义的关键地方。

/**
 1. ConfigurationClassParser的方法
 2. <p>
 3. 解析、注册 配置类内部的成员(嵌套)类,也就是内部类。最终还是会调用外部的doProcessConfigurationClass方法
 */
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
                                  Predicate<String> filter) throws IOException {
    /*
     * 获取全部内部类的SourceClass集合memberClasses
     *
     * 还记得我们之前在IoC容器初始化的时候,讲的扩展标签解析的doScan方法内的第二个isCandidateComponent方法吗
     * 该方法将非静态内部类都排除了,因此,非静态内部类的bean定义还没有注册到容器中。
     *
     * 而这里的getMemberClasses将获取所有的内部类,包括静态的和非静态的,其中,非静态内部类的bean定义就是在这里注册的
     */
    Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
    //如果memberClasses不为空
    if (!memberClasses.isEmpty()) {
        //需要处理的配置类集合
        List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
        for (SourceClass memberClass : memberClasses) {
            //如果内部类也是配置类
            if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
                    !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
                //加入到candidates
                candidates.add(memberClass);
            }
        }
        //同样需要排序,这里的OrderComparator就不支持注解了
        OrderComparator.sort(candidates);
        /*
         * 遍历candidates,按照排序顺序依次处理
         */
        for (SourceClass candidate : candidates) {
            //如果importStack包含此外部配置类,那么说明import循环依赖,直接抛出异常: "A circular @Import has been detected……"
            //importStack属性用于判断import重复依赖
            if (this.importStack.contains(configClass)) {
                this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
            } else {
                //当前外部配置类configClass入栈
                this.importStack.push(configClass);
                try {
                    /*
                     * 调用processConfigurationClass方法,处理当前内部配置类
                     * 这里的asConfigClass方法将当前外部配置类的设置到内部配置类的importedBy集合中,表示算作被外部类import引入进来的
                     */
                    processConfigurationClass(candidate.asConfigClass(configClass), filter);
                } finally {
                    //当前外部配置类configClass出栈
                    this.importStack.pop();
                }
            }
        }
    }
}

processPropertySource处理@PropertySource属性源注解

  该方法用于解析配置类上的@PropertySources以及@PropertySource注解(@PropertySources相当于一个@PropertySource注解的集合)。
  通过这两个注解的方式,引入本地属性源,用来替代XML的资源引入,比如< context:property-placeholder/>标签,这个注解可重复出现。属性源将会被添加到到environment环境变量中。
  @PropertySource的相关属性如下:

  • value:一个字符串数组,存放本地配置文件的路径字符串,一个@PropertySource注解可以引入多个属性配置文件;该属性只有有一个值。同样,这里的路径字符串支持${…:…}占位符解析,但是只会使用environment环境变量中的属性源。一般我们只需要设置value属性即可!
  • name:属性源的名称,如果没有指定,那么将会自动生成;
  • encoding:文件加载解析的字符集;
  • factory:用于创建属性源的工厂的类型,默认为PropertySourceFactory.class;
/**
 * PropertySourceFactory的属性
 * 默认属性源工厂
 * 如果没有指定PropertySource的factory属性,或者指定的属性值为PropertySourceFactory.class
 * 那么以该DefaultPropertySourceFactory作为属性源工厂
 */
private static final PropertySourceFactory DEFAULT_PROPERTY_SOURCE_FACTORY = new DefaultPropertySourceFactory();


/**
 * ConfigurationClassParser的方法
 * <p>
 * 处理给定的@PropertySource注解元数据
 *
 * @param propertySource 找到的@PropertySource注解的元数据,实际上就是一个map,包含了当前注解的属性和对应的值
 */
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
    //获取name属性,表示属性源的名称
    String name = propertySource.getString("name");
    if (!StringUtils.hasLength(name)) {
        name = null;
    }
    //获取encoding属性,表示编码字符集
    String encoding = propertySource.getString("encoding");
    if (!StringUtils.hasLength(encoding)) {
        encoding = null;
    }
    //获取本地配置文件的路径字符串数组,一个@PropertySource注解可以引入多个属性配置文件
    String[] locations = propertySource.getStringArray("value");
    //断言只有有一个文件路径
    Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
    //获取ignoreResourceNotFound属性的值,表示是否允许配置文件找不到
    boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
    //获取factory属性的值,也就是PropertySourceFactory的class,用来创建属性源,默认值就是PropertySourceFactory.class
    Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
    //获取PropertySourceFactory,用于创建属性源工厂
    PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
            DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
    /*
     * 遍历本地配置文件的路径字符串数组,依次加载配置文件,添加属性源
     */
    for (String location : locations) {
        try {
            /*
             * 通过环境变量,解析路径字符串中的占位符,使用严格模式,遇到没有默认值的无法解析的占位符将抛出IllegalArgumentException异常
             * 这说明我们指定的@PropertySource注解中的location支持${.. : ..}占位符,但是只会从environment环境变量中查找属性,这一点要注意
             */
            String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
            //将配置文件加载成为一个Resource资源
            Resource resource = this.resourceLoader.getResource(resolvedLocation);
            /*
             * 根据当前name、resource、encoding创建一个属性源,如果没有name那么将会生成默认的name,随后添加属性源
             */
            addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
        } catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) {
            // Placeholders not resolvable or resource not found when trying to open it
            if (ignoreResourceNotFound) {
                if (logger.isInfoEnabled()) {
                    logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
                }
            } else {
                throw ex;
            }
        }
    }
}

addPropertySource添加属性源到environment

  该方法的源码就印证了我们在之前关于PropertySourcesPlaceholderConfigurer的文章的结尾的话语,即@PropertySource注解解析后的属性源将会被添加到environment环境变量中的属性源集合propertySources中。
  这个propertySources集合我们在IoC容器初始化的第一篇文章的setLocations方法中就见过了,该集合在setLocations方法中就初始化了著名的systemProperties — JVM系统属性属性源以及systemEnvironment - 系统环境属性源。在根据environment替换占位符的时候,就是从这个属性源集合中依次遍历、查找的,因此systemProperties — JVM系统属性属性源的优先级最高。
  通过@PropertySource注解添加的属性源,越后添加的属性源查找的优先级越高,但是仍低于systemProperties和systemEnvironment这两个系统级别的属性源。

/**
 * ConfigurationClassParser的属性
 * 属性源的名称集合
 */
private final List<String> propertySourceNames = new ArrayList<>();

/**
 * 环境变量,在创建解析器的时候就初始化了
 */
private final Environment environment;

/**
 1. ConfigurationClassParser的方法
 2. <p>
 3. 添加属性源到environment环境变量中
 4.  5. @param propertySource 当前@PropertySource指定的配置文件对应的属性源
 */
private void addPropertySource(PropertySource<?> propertySource) {
    //获取属性源的name
    String name = propertySource.getName();
    /*
     * 获取environment环境变量中的getPropertySources属性源集合,这个属性源集合,我们在IoC容器的最最最开始的setLocations方法中就见过了
     * 该集合在setLocations方法中就初始化了著名的systemProperties — JVM系统属性属性源以及systemEnvironment - 系统环境属性源
     * 在根据environment替换占位符的时候,就是从这个属性源集合中依次遍历、查找的,因此systemProperties — JVM系统属性属性源的优先级最高
     */
    MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();
    /*
     * 如果属性源名称集合中已包含该名称name,那么就扩展这个名字的属性源
     * 因为一个@PropertySource可能指定多个配置文件
     */
    if (this.propertySourceNames.contains(name)) {
        // We've already added a version, we need to extend it
        //获取该名字的属性源
        PropertySource<?> existing = propertySources.get(name);
        //如果不为null
        if (existing != null) {
            PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource ?
                    ((ResourcePropertySource) propertySource).withResourceName() : propertySource);
            if (existing instanceof CompositePropertySource) {
                //当前属性源加入到existing属性源集合的开头
                ((CompositePropertySource) existing).addFirstPropertySource(newSource);
            } else {
                if (existing instanceof ResourcePropertySource) {
                    existing = ((ResourcePropertySource) existing).withResourceName();
                }
                //当前属性源加入到属性源集合的开头
                CompositePropertySource composite = new CompositePropertySource(name);
                composite.addPropertySource(newSource);
                composite.addPropertySource(existing);
                propertySources.replace(name, composite);
            }
            return;
        }
    }

    /*
     * 到这里,表示属性源名称集合中不包含该名称name
     * 那么添加一个新name的属性源到环境变量的propertySources属性源集合中,同时将name加入到propertySourceNames集合中
     * 越后添加的属性源查找的优先级越高,但是低于systemProperties和systemEnvironment这两个系统级别的属性源
     */

    //如果是第一个加载的@PropertySource注解属性源
    if (this.propertySourceNames.isEmpty()) {
        //那么加入到propertySources属性源集合的尾部,查找的优先级最低
        propertySources.addLast(propertySource);
    }
    //否则
    else {
        //获取最后一个添加的属性源名称
        String firstProcessed = this.propertySourceNames.get(this.propertySourceNames.size() - 1);
        //在propertySources中的名为firstProcessed的属性源的索引处添加该属性源,原索引以及之后的属性源向后移动一位
        //即越后添加的属性源优先级越高
        propertySources.addBefore(firstProcessed, propertySource);
    }
    this.propertySourceNames.add(name);
}

ComponentScanAnnotationParser.parse处理@ComponentScan组件扫描注解

  ComponentScanAnnotationParser的parse方法用于处理@ComponentScan组件扫描注解,根据指定的包路径扫描出全部复合条件的bean定义。
  该方法主要是进行@ComponentScan注解的属性解析,真正的扫描包还是通过ClassPathBeanDefinitionScanner的doScan方法进行扫描的,无论是注解配置还是XML的配置,扫描包都是调用的这个方法,我们在此前< context:component-scan/>的注解解析文章中已经讲过了,该方法将会扫描并且注册这些指定包路径下的bean定义。
  @ComponentScan的相关属性如下,实际上和< context:component-scan/>的相关属性都差不多,我们在讲这个标签的时候就详细讲解过了:

  • useDefaultFilters:是否注册默认类型过滤器,默认值true。
    注册默认过滤器就是尝试添加@Component、@ManagedBean、@Named这三个注解类型过滤器到includeFilters缓存集合中!
    这表示将会注册所有具有@Component注解及其派生注解的注解标志的类,比如@Component、@Repository、@Service、@Controller、@Configuration,还支持扫描注册 Java EE 6 的注解,比如@ManagedBean,以及JSR-330的注解,比如@Named。
  • nameGenerator :指定的beanName生成器的class,默认值是BeanNameGenerator.class,将会使用AnnotationBeanNameGenerator生成beanName。
  • scopedProxy、scopeResolver:使用代理模式,通常在web应用中使用。
  • resourcePattern:控制符合组件检测条件的类文件,Spring推荐使用includeFilters和excludeFilters。
  • includeFilters:包含的类型过滤器,默认空集合。如果扫描到的组件满足该集合中任意的类型过滤器,那么算作有资格作为候选组件。后遍历includeFilters。
  • excludeFilters:排除的类型过滤器,默认空集合。如果扫描到的组件满足该集合中任意的类型过滤器,那么算作没有资格作为候选组件。先遍历excludeFilters。
    默认添加一个AbstractTypeHierarchyTraversingFilter匿名对象,将会排除当前的配置类的扫描。
  • lazyInit:扫描到的组件是否都延迟初始化,默认false。
  • basePackages:要扫描的包路径字符串数组。传递的字符串支持${…:…}占位符,将会使用environment环境变量解析,还支持以","、";"、" “、”\t"、"\n"中的任意字符作为分隔符来表示传递了多个包路径。默认是个空数组。
  • basePackageClasses:可以指定了一批类的class,Spring将解析class所在的包路经作为扫描包路径,功能和basePackages一致。默认是个空数组。
    如果basePackages和basePackageClasses都没有指定值,那么默认扫描当前@ComponentScan注解所在的类所在的包下面的所有bean定义。
//--------ComponentScanAnnotationParser的相关属性,在构造器中初始化-----------

private final Environment environment;

private final ResourceLoader resourceLoader;

private final BeanNameGenerator beanNameGenerator;

private final BeanDefinitionRegistry registry;

/**
 * ConfigurableApplicationContext的属性
 * <p>
 * 分隔符常量,支持","、";"、" "、"\t"、"\n"中的任意分隔符
 */
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";


/**
 * ComponentScanAnnotationParser的方法
 * <p>
 * 解析@ComponentScan注解,获取解析到的bean定义集合
 *
 * @param componentScan  一个@ComponentScan注解的属性集合
 * @param declaringClass 当前配置类的className
 * @return 解析到的bean定义集合
 */
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    /*
     * 创建一个类路径Bean定义扫描器
     * 通过useDefaultFilters属性的值判断是否注册默认的类型过滤器,默认值true,即注册默认类型过滤器
     *
     * 这个默认类型过滤器我们在此前IoC容器初始化源码的<context:component-scan/>扩展标签解析的时候就讲了:
     * 注册默认过滤器就是尝试添加@Component、@ManagedBean、@Named这三个注解类型过滤器到includeFilters缓存集合中!
     *
     * 这表示将会注册所有具有@Component注解及其派生注解的注解标志的类,比如@Component、@Repository、@Service、@Controller、@Configuration,
     * 还支持扫描注册 Java EE 6 的注解,比如@ManagedBean,以及JSR-330的注解,比如@Named
     */
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
            componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

    /*
     * 获取beanName生成器,默认是AnnotationBeanNameGenerator
     */

    //获取nameGenerator属性值,即beanName生成器的class,默认值为BeanNameGenerator.class
    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
    //判断是否是默认值,如果是默认值,那么使用当前创建ComponentScanAnnotationParser对象时指定的beanName生成器,
    //也就是ConfigurationClassPostProcessor类中的componentScanBeanNameGenerator,即AnnotationBeanNameGenerator
    //否则反射调用无参构造器,初始化指定类型的beanName生成器实例
    boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
    scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
            BeanUtils.instantiateClass(generatorClass));

    //生成代理对象的模式,通常在web应用中使用
    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
    if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
        //设置指定的模式
        scanner.setScopedProxyMode(scopedProxyMode);
    } else {
        //自动选择JDK代理或者CGLib代理
        Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
        scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
    }
    //控制符合组件检测条件的类文件,Spring推荐使用includeFilters和excludeFilters
    scanner.setResourcePattern(componentScan.getString("resourcePattern"));
    //遍历每一个Filter
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
        //解析每一个Filter成为TypeFilter类型过滤器集合,继续遍历该集合
        for (TypeFilter typeFilter : typeFiltersFor(filter)) {
            //设置到includeFilters属性中
            scanner.addIncludeFilter(typeFilter);
        }
    }
    //遍历每一个Filter
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
        //解析每一个Filter成为TypeFilter类型过滤器集合,继续遍历该集合
        for (TypeFilter typeFilter : typeFiltersFor(filter)) {
            //设置到excludeFilters属性中
            scanner.addExcludeFilter(typeFilter);
        }
    }
    //获取lazyInit加载值,表示是否延迟初始化,默认false
    boolean lazyInit = componentScan.getBoolean("lazyInit");
    if (lazyInit) {
        //设置给beanDefinitionDefaults属性,这是设置一个默认值属性
        scanner.getBeanDefinitionDefaults().setLazyInit(true);
    }
    /*
     * 扫描包
     */

    /*
     * 解析后的包路径字符串
     * Spring将会对其解析、扫描其中的bean定义
     */
    Set<String> basePackages = new LinkedHashSet<>();
    /*
     * 获取basePackages属性数组,也就是传递的包路径字符串,默认是个空数组
     */
    String[] basePackagesArray = componentScan.getStringArray("basePackages");
    for (String pkg : basePackagesArray) {
        /*
         * 通过环境变量解析传递的路径字符串中的占位符,随后根据分隔符分割为一个路径字符串数组
         * 支持以","、";"、" "、"\t"、"\n"中的任意字符作为分隔符来表示传递了多个包路径
         */
        String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        Collections.addAll(basePackages, tokenized);
    }
    /*
     * 获取basePackageClasses属性数组,默认是个空数组
     * basePackageClasses属性可以指定了一批类的class,Spring将解析class所在的包路径作为扫描路径
     */
    for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
        //解析class的packageName,存入basePackages包路径字符串中
        basePackages.add(ClassUtils.getPackageName(clazz));
    }
    /*
     * 如果解析后的basePackages包数组为空,即没有手动传递包路经
     */
    if (basePackages.isEmpty()) {
        //那么将当前@ComponentScan注解所在的类所属的包路径作为扫描的包路径
        //也就是,默认扫描当前@ComponentScan注解所在的包下面的所有bean定义
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }
    /*
     * 最后添加一个ExcludeFilter到excludeFilters属性中,表示排除当前的配置类的扫描
     */
    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
        @Override
        protected boolean matchClassName(String className) {
            return declaringClass.equals(className);
        }
    });
    /*
     * 上面都是一些准备的逻辑,doScan方法才是真正执行扫描的逻辑,通过ClassPathBeanDefinitionScanner执行
     * 无论是注解配置还是XML的配置,扫描包都是调用的这个方法,我们在此前<context:component-scan/>的注解解析文章中已经讲过了
     * 该方法将会扫描并且注册这些指定包路径下的bean定义
     */
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}

typeFiltersFor解析类型过滤器

  ComponentScanAnnotationParser的typeFiltersFor方法用于解析includeFilters或者excludeFilters属性对象,获取解析出来的类型过滤器集合。
  @ComponentScan注解的includeFilters或者excludeFilters属性写法如下:
image.png

/**
 1. ComponentScanAnnotationParser的方法
 2. <p>
 3. 解析includeFilters或者excludeFilters属性对象,获取解析出来的类型过滤器集合
 4.  5. @param filterAttributes includeFilters或者excludeFilters属性对象
 6. @return 解析出来的类型过滤器集合
 */
private List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
    //用于保存解析出来的类型过滤器
    List<TypeFilter> typeFilters = new ArrayList<>();
    //获取type属性值
    FilterType filterType = filterAttributes.getEnum("type");
    /*
     * 获取classes属性值,遍历
     */
    for (Class<?> filterClass : filterAttributes.getClassArray("classes")) {
        switch (filterType) {
            //添加注解类型过滤器
            case ANNOTATION:
                Assert.isAssignable(Annotation.class, filterClass,
                        "@ComponentScan ANNOTATION type filter requires an annotation type");
                @SuppressWarnings("unchecked")
                Class<Annotation> annotationType = (Class<Annotation>) filterClass;
                typeFilters.add(new AnnotationTypeFilter(annotationType));
                break;
            //添加类或者接口的类型过滤器
            case ASSIGNABLE_TYPE:
                typeFilters.add(new AssignableTypeFilter(filterClass));
                break;
            //添加自定义类型过滤器
            case CUSTOM:
                Assert.isAssignable(TypeFilter.class, filterClass,
                        "@ComponentScan CUSTOM type filter requires a TypeFilter implementation");

                TypeFilter filter = ParserStrategyUtils.instantiateClass(filterClass, TypeFilter.class,
                        this.environment, this.resourceLoader, this.registry);
                typeFilters.add(filter);
                break;
            //其他类型的过滤器将抛出异常
            default:
                throw new IllegalArgumentException("Filter type not supported with Class value: " + filterType);
        }
    }
    /*
     * 获取pattern属性值,遍历
     */
    for (String expression : filterAttributes.getStringArray("pattern")) {
        switch (filterType) {
            //创建一个AspectJTypeFilter,expression应该是一个AspectJ表达式,通过该表达式匹配类或者接口(及其子类、子接口)
            case ASPECTJ:
                typeFilters.add(new AspectJTypeFilter(expression, this.resourceLoader.getClassLoader()));
                break;
            //创建一个RegexPatternTypeFilter,expression应该是一个正则表达式,通过该表达式匹配类或者接口(及其子类、子接口)
            case REGEX:
                typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(expression)));
                break;
            //其他类型的过滤器将抛出异常
            default:
                throw new IllegalArgumentException("Filter type not supported with String pattern: " + filterType);
        }
    }
    //返回解析出来的类型过滤器集合
    return typeFilters;
}

processImports处理@Import注解

  processImports方法用于处理配置类上的@Import注解。@Import注解可以传递一个class的数组,用于引入bean定义。在处理上,针对传递的class分为三种类型分类处理:

实现了ImportSelector接口的class,该class对应的类本身不会被注册为bean定义,但是它的selectImports方法返回的类路径数组中的类将可能会被注册为bean定义。但是在该方法中仅仅是递归调用processImports方法,对于返回的类路径数组中的符合条件的类继续解析,直到它是一个普通类或者ImportBeanDefinitionRegistrar类型。
实现了ImportBeanDefinitionRegistrar接口的class,该class对应的类本身不会被注册为bean定义,但是它的registerBeanDefinitions方法可用于自定义注册bean定义。但是在该方法中仅仅是加入importBeanDefinitionRegistrars缓存中,后续通过reader.loadBeanDefinitions 方法统一处理。
普通类型的class,该class对应的类将尝试被注册为bean定义。但是在该方法中仅仅是将其当作配置类递归调用processConfigurationClass方法处理,并且会注册到configurationClasses缓存中,后续通过reader.loadBeanDefinitions 方法统一处理。
还会将被引入普通class的的全路径名字符串和引入该bean类的AnnotationMetadata元数据通过registerImport方法存入importStack栈的imports缓存中,这有这里会调用该方法,后面的ImportAwareBeanPostProcessor.postProcessBeforeInitialization方法就可能用到这里的存入的数据。
因此通过@Import注解引入的bean定义不会在该方法中注册,而是在后续通过reader.loadBeanDefinitions 方法统一注册。

/**
 * ConfigurationClassParser的方法
 * <p>
 * 处理@Import注解
 *
 * @param configClass             表示当前配置类的对象
 * @param currentSourceClass      源类
 * @param importCandidates        @Import注解引入的类的SourceClass集合
 * @param exclusionFilter         类型过滤器
 * @param checkForCircularImports 是否校验循环import依赖
 */
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
                            Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
                            boolean checkForCircularImports) {
    //如果没有引入任何类,那么直接返回
    if (importCandidates.isEmpty()) {
        return;
    }
    //检测是否有循环import的情况
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new ConfigurationClassParser.CircularImportProblem(configClass, this.importStack));
    } else {
        //当前配置类configClass入栈
        this.importStack.push(configClass);
        try {
            //遍历sourceClass集合
            for (SourceClass candidate : importCandidates) {
                //如果Import的类实现了ImportSelector接口
                if (candidate.isAssignable(ImportSelector.class)) {
                    // Candidate class is an ImportSelector -> delegate to it to determine imports
                    Class<?> candidateClass = candidate.loadClass();
                    //反射创建一个ImportSelector对象
                    ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                            this.environment, this.resourceLoader, this.registry);
                    //获取从导入候选项中排除类的谓词
                    Predicate<String> selectorFilter = selector.getExclusionFilter();
                    //连接这两个谓词
                    if (selectorFilter != null) {
                        exclusionFilter = exclusionFilter.or(selectorFilter);
                    }
                    //如果selector还属于DeferredImportSelector接口,那么将在最后执行
                    if (selector instanceof DeferredImportSelector) {
                        //存入ImportSelector的延迟处理器中,后面会统一在外部parse方法末尾通过this.deferredImportSelectorHandler.process()延迟处理
                        this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
                    } else {
                        //获取当前ImportSelector的selectImports方法返回值,也就是要导入到容器中的组件全类名数组,可以指定多个
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        //遍历要导入到容器中的组件全类名数组,排除符合exclusionFilter条件的组件类名,对于剩下的组件全类名进行加载成为SourceClass集合
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                        /*
                         * 递归调用processImports方法,对于从当前import类中解析出来的importSourceClasses继续解析
                         */
                        processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
                    }
                }
                //如果Import的类实现了ImportBeanDefinitionRegistrar接口
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    // Candidate class is an ImportBeanDefinitionRegistrar ->
                    // delegate to it to register additional bean definitions
                    Class<?> candidateClass = candidate.loadClass();
                    //反射创建一个ImportBeanDefinitionRegistrar对象registrar
                    ImportBeanDefinitionRegistrar registrar =
                            ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                    this.environment, this.resourceLoader, this.registry);
                    //当前registrar和importingClassMetadata存入configClass的importBeanDefinitionRegistrars缓存中,后续才会处理
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                }
                //如果Import的类是普通类型
                else {
                    // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                    // process it as an @Configuration class
                    //存入importStack栈的imports缓存中
                    this.importStack.registerImport(
                            currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                    //将其当作配置类递归调用processConfigurationClass方法处理,并且会注册到configurationClasses缓存中
                    //后续通过reader.loadBeanDefinitions 方法统一处理
                    //这里的asConfigClass方法将当前外部配置类的设置到Import类的importedBy集合中,表示算作被外部类Import引入进来的
                    processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
                }
            }
        } catch (BeanDefinitionStoreException ex) {
            throw ex;
        } catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                    "Failed to process import candidates for configuration class [" +
                            configClass.getMetadata().getClassName() + "]", ex);
        } finally {
            //当前配置类configClass出栈
            this.importStack.pop();
        }
    }
}

asSourceClasses获取符合条件的SourceClass集合

  该方法将从selectImports的返回值数组中继续筛选获取不匹配exclusionFilter排除过滤器的className创建SourceClass,并返回一个SourceClass集合。
  默认的exclusionFilter就DEFAULT_EXCLUSION_FILTER,该filter的条件是如果类名以"java.lang.annotation."或者"org.springframework.stereotype."开头,就返回true,或者返回false。实际含义就是如果是这些注解类型,那就丢弃。

/**
 * ConfigurationClassParser的方法
 * <p>
 * 获取符合filter条件的类名的SourceClass集合
 */
private Collection<SourceClass> asSourceClasses(String[] classNames, Predicate<String> filter) throws IOException {
    List<SourceClass> annotatedClasses = new ArrayList<>(classNames.length);
    for (String className : classNames) {
        annotatedClasses.add(asSourceClass(className, filter));
    }
    //返回SourceClass集合
    return annotatedClasses;
}

/**
 * ConfigurationClassParser的属性
 * 替代被排除的className的SourceClass对象
 */
private final SourceClass objectSourceClass = new SourceClass(Object.class);


/**
 * ConfigurationClassParser的方法
 * <p>
 * 获取符合filter条件的类名的SourceClass
 */
SourceClass asSourceClass(@Nullable String className, Predicate<String> filter) throws IOException {
    //如果符合过滤条件,那么返回objectSourceClass常量,后续将不会注入该类型的bean实例
    //注意这里还是返回了一个objectSourceClass,而不是null,后面会处理
    if (className == null || filter.test(className)) {
        return this.objectSourceClass;
    }
    //如果class名以java开头,这表示位于rt.jar核心包中的核心类
    if (className.startsWith("java")) {
        // Never use ASM for core java types
        try {
            //直接传递生成的class对象
            return new SourceClass(ClassUtils.forName(className, this.resourceLoader.getClassLoader()));
        } catch (ClassNotFoundException ex) {
            throw new NestedIOException("Failed to load class [" + className + "]", ex);
        }
    }
    //根据className,返回SourceClass
    return new SourceClass(this.metadataReaderFactory.getMetadataReader(className));
}

@Import注解使用

  我们测试三种class类型,位于com.spring.source.imports包下:

/**
 * @author lx
 */
public class BeanTest {

    /**
     * 普通class
     */
    public static class NormalBean {}

    /**
     * 实现了ImportSelector的class
     */
    public static class ImportSelectorBean implements ImportSelector {

        /**
         * 返回的类路径字符串数组,将会注册这些类型的bean定义
         */
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            String[] strings = new String[2];
            strings[0] = "com.spring.source.imports.BeanTest.ImportSelectorBean1";
            strings[1] = "com.spring.source.imports.BeanTest.ImportSelectorBean2";
            return strings;
        }


    }

    /**
     * 实现了ImportBeanDefinitionRegistrar的class
     */
    public static class ImportBeanDefinitionRegistrarBean implements ImportBeanDefinitionRegistrar {
        /**
         * 可以自定义注册bean定义的逻辑
         */
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
            //创建bean定义
            RootBeanDefinition beanDefinition1 = new RootBeanDefinition();
            beanDefinition1.setBeanClass(Object.class);
            RootBeanDefinition beanDefinition2 = new RootBeanDefinition();
            beanDefinition2.setBeanClass(Object.class);
            //注册bean定义
            registry.registerBeanDefinition("o1", beanDefinition1);
            registry.registerBeanDefinition("o2", beanDefinition2);
        }
    }


    public static class ImportSelectorBean1 {}

    public static class ImportSelectorBean2 {}
}

我们的配置类com.spring.source.imports.ImportBean:

@Configuration
@Import({BeanTest.NormalBean.class, BeanTest.ImportSelectorBean.class,
        BeanTest.ImportBeanDefinitionRegistrarBean.class})
public class ImportBean { }

配置文件spring-config-import.xml:

<context:component-scan base-package="com.spring.source.imports"/>

测试:

@Test
public void importTest() {
    //设置环境变量
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring-config-import.xml");
    //获取普通bean实例
    System.out.println(ac.getBean(BeanTest.NormalBean.class));
    //获取通过ImportSelector引入的bean实例
    System.out.println(ac.getBean(BeanTest.ImportSelectorBean1.class));
    System.out.println(ac.getBean(BeanTest.ImportSelectorBean2.class));
    //获取通过ImportBeanDefinitionRegistrarBean手动注册的bean实例
    System.out.println(ac.getBean("o1"));
    System.out.println(ac.getBean("o2"));

    //获取ImportSelector实例本身,获取不到,将会报错
    System.out.println(ac.getBean(BeanTest.ImportSelectorBean.class));
    //获取ImportBeanDefinitionRegistrarBean实例本身,获取不到,将会报错
    System.out.println(ac.getBean(BeanTest.ImportBeanDefinitionRegistrarBean.class));
}

一次测试的结果如下:

com.spring.source.imports.BeanTest$NormalBean@5119fb47
com.spring.source.imports.BeanTest$ImportSelectorBean1@7193666c
com.spring.source.imports.BeanTest$ImportSelectorBean2@20deea7f
java.lang.Object@3835c46
java.lang.Object@1dde4cb2

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.spring.source.imports.BeanTest$ImportSelectorBean' available

可以看到:

对于普通class,将会把该class本身注入到容器中;
对于ImportSelectorBean的class,将会把selectImports方法返回的一批class注入到容器中。该class本身不会注入到容器中。
源码中还要求排除匹配exclusionFilter过滤器的类名。默认的filter就DEFAULT_EXCLUSION_FILTER,该filter的条件是如果类名以"java.lang.annotation."或者"org.springframework.stereotype."开头,就返回true,或者返回false。
对于ImportBeanDefinitionRegistrarBean的class,可以通过registerBeanDefinitions方法自定义的注册一批bean定义,后面将会将实例化。该class本身不会注入到容器中。

/**
 * 普通class
 */
public static class NormalBean {
}

/**
 * 实现了ImportSelector的class
 */
public static class ImportSelectorBean implements ImportSelector {

    /**
     * 返回的类路径字符串数组,将会注册这些类型的bean定义
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        String[] strings = new String[2];
        strings[0] = "com.spring.source.imports.BeanTest.ImportSelectorBean1";
        strings[1] = "com.spring.source.imports.BeanTest.ImportSelectorBean2";
        return strings;
    }

    @Override
    public Predicate<String> getExclusionFilter() {
        return "com.spring.source.imports.BeanTest.ImportSelectorBean1"::equals;
    }
}

这个过滤器的意思就是不注册ImportSelectorBean1的bean,我们再次测试,发现更早的抛出异常,因为容器中没有注册ImportSelectorBean1类型的bean实例:

com.spring.source.imports.BeanTest$NormalBean@7193666c

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.spring.source.imports.BeanTest$ImportSelectorBean1' available

parser.validate校验配置类

  在通过parser.parse方法解析每一个配置类之后,随即调用parser.validate()方法校验所有解析之后的配置类,也就是ConfigurationClass。

如果当前配置类具有@Configuration注解,并且proxyBeanMethods属性为true,默认就是true:
如果当前配置类是被final修饰的最终类,那么抛出异常:"@Configuration class ‘%s’ may not be final. Remove the final modifier to continue.",因为它不能被CGLIB代理。
如果@Bean注解标注的方法是final或者private且非static修饰的方法,那么抛出异常:"@Bean method ‘%s’ must not be private or final; change the method’s modifiers to continue",因为它不能被CGLiB代理。注意@Bean方法可以被static修饰。

/**
 * ConfigurationClassParser的方法
 * <p>
 * 校验全部ConfigurationClass
 */
public void validate() {
    for (ConfigurationClass configClass : this.configurationClasses.keySet()) {
        //校验每一个configClass
        configClass.validate(this.problemReporter);
    }
}

/**
 * ConfigurationClass的方法
 *
 * @param problemReporter 问题报告器
 */
public void validate(ProblemReporter problemReporter) {
    // A configuration class may not be final (CGLIB limitation) unless it declares proxyBeanMethods=false
    Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
    //如果当前配置类具有@Configuration注解,并且proxyBeanMethods属性为true(默认就是true)
    if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) {
        //如果当前配置类是被final修饰的最终类,那么抛出异常:"@Configuration class '%s' may not be final. Remove the final modifier to continue."
        //因为它不能被CGLIB代理
        if (this.metadata.isFinal()) {
            problemReporter.error(new FinalConfigurationProblem());
        }
        //校验全部@Bean注解方法
        for (BeanMethod beanMethod : this.beanMethods) {
            beanMethod.validate(problemReporter);
        }
    }
}

/**
 * BeanMethod的方法
 * 校验@Bean注解标注的方法
 */
@Override
public void validate(ProblemReporter problemReporter) {
    //如果是静态方法,不需要校验,直接返回
    if (getMetadata().isStatic()) {
        // static @Bean methods have no constraints to validate -> return immediately
        return;
    }
    //如果当前方法所属配置类具有@Configuration注解
    if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
        //如果当前方法不能被重写,那么抛出异常:"@Bean method '%s' must not be private or final; change the method's modifiers to continue"
        //因为只有可重写的方法才能被CGLiB代理
        //如果是final、static、private修饰的方法,那么isOverridable方法就返回true
        if (!getMetadata().isOverridable()) {
            // instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
            problemReporter.error(new NonOverridableMethodError());
        }
    }
}

new ConfigurationClassBeanDefinitionReader 创建bean定义加载器

  ConfigurationClassPostProcessor将使用ConfigurationClassBeanDefinitionReader来加载、注册此前通过parse方法找到的可能存在的bean定义。

//----------ConfigurationClassBeanDefinitionReader的相关属性

private final BeanDefinitionRegistry registry;

private final SourceExtractor sourceExtractor;

private final ResourceLoader resourceLoader;

private final Environment environment;

private final BeanNameGenerator importBeanNameGenerator;

private final ImportRegistry importRegistry;

private final ConditionEvaluator conditionEvaluator;

/**
 * ConfigurationClassBeanDefinitionReader构造器
 *
 * @param registry                bean定义要存入的注册表
 * @param sourceExtractor         简单的策略,允许工具控制源元数据如何附加到 bean 定义元数据。
 * @param resourceLoader          资源加载器
 * @param environment             环境变量
 * @param importBeanNameGenerator import方式引入的bean的beanName生成器
 * @param importRegistry          import方式引入的bean注册表
 */
ConfigurationClassBeanDefinitionReader(BeanDefinitionRegistry registry, SourceExtractor sourceExtractor,
                                       ResourceLoader resourceLoader, Environment environment, BeanNameGenerator importBeanNameGenerator,
                                       ImportRegistry importRegistry) {
    //初始化一批属性
    this.registry = registry;
    this.sourceExtractor = sourceExtractor;
    this.resourceLoader = resourceLoader;
    this.environment = environment;
    this.importBeanNameGenerator = importBeanNameGenerator;
    this.importRegistry = importRegistry;
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}

reader.loadBeanDefinitions 加载bean定义

  通过reader加载、注册所有configClasses中的bean定义,也就是对configClasses中的@Import、@Bean、@ImportResource等注解中可能的bean定义进行解析和注册。
  该方法结束,那么processConfigBeanDefinitions方法的主要逻辑就结束了。

/**
 * ConfigurationClassBeanDefinitionReader的方法
 * <p>
 * 向注册表注册 bean 定义
 *
 * @param configurationModel 解析后的ConfigurationClass配置类集合
 */
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
    //评估@Conditional注释,判断当前配置类的解析否需要跳过,将会跟踪结果并考虑到"importBy"。
    TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
    //遍历解析后的ConfigurationClass配置类集合,加载bean定义
    for (ConfigurationClass configClass : configurationModel) {
        //从ConfigurationClass加载bean定义
        loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
    }
}

reader.loadBeanDefinitions 加载bean定义

  通过reader加载、注册所有configClasses中的bean定义,也就是对configClasses中的@Import、@Bean、@ImportResource等注解中可能的bean定义进行解析和注册。
  该方法结束,那么processConfigBeanDefinitions方法的主要逻辑就结束了。

/**
 * ConfigurationClassBeanDefinitionReader的方法
 * <p>
 * 向注册表注册 bean 定义
 *
 * @param configurationModel 解析后的ConfigurationClass配置类集合
 */
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
    //评估@Conditional注释,判断当前配置类的解析否需要跳过,将会跟踪结果并考虑到"importBy"。
    TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
    //遍历解析后的ConfigurationClass配置类集合,加载bean定义
    for (ConfigurationClass configClass : configurationModel) {
        //从ConfigurationClass加载bean定义
        loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
    }
}

new TrackedConditionEvaluator 跟踪条件评估器

  ConfigurationClassBeanDefinitionReader的内部类,同样是用于判断当前配置类的解析否需要跳过,和之前的Evaluator区别是除了评估@Conditional注解之外,还会跟踪结果并考虑到"importedBy"。
  它的shouldSkip方法很简单,如果当前configClass是被引入的,并且引入类都是被跳过的,那么当前configClass也应该被跳过,否则通过原始的conditionEvaluator.shouldSkip方法判断是否需要跳过,这里的phase生效的阶段参数为REGISTER_BEAN,即注册bean的阶段。
  解析后的结果将会存入skipped缓存,后续再来查询时将不会再次解析。

/**
 1. ConfigurationClassBeanDefinitionReader的内部类
 2. 评估@Conditional注解,跟踪结果并考虑到"importedBy"
 */
private class TrackedConditionEvaluator {

    /**
     * ConfigurationClass的缓存,避免后续重复校验应该跳过解析
     */
    private final Map<ConfigurationClass, Boolean> skipped = new HashMap<>();

    /**
     * 是否应该跳过解析
     *
     * @param configClass
     * @return
     */
    public boolean shouldSkip(ConfigurationClass configClass) {
        //从缓存获取当前configClass的是否应该跳过的结果
        Boolean skip = this.skipped.get(configClass);
        //如果缓存为null,那么解析
        if (skip == null) {
            //如果是被其他类引入的
            if (configClass.isImported()) {
                //所有的引入类被跳过的标记,默认true
                boolean allSkipped = true;
                //获取引入类
                for (ConfigurationClass importedBy : configClass.getImportedBy()) {
                    //如果引入类不应该被跳过
                    if (!shouldSkip(importedBy)) {
                        //那么allSkipped为false,结束循环
                        allSkipped = false;
                        break;
                    }
                }
                //如果所有的引入类被跳过,那么skip设置为true,表示当前被引入的类应该被跳过
                if (allSkipped) {
                    // The config classes that imported this one were all skipped, therefore we are skipped...
                    skip = true;
                }
            }
            //如果skip还是为null
            if (skip == null) {
                //那么调用conditionEvaluator的shouldSkip方法继续判断,这里的phase生效的阶段参数为REGISTER_BEAN,即注册bean的阶段
                //这个方法我们此前就讲过了
                skip = conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN);
            }
            //存入缓存
            this.skipped.put(configClass, skip);
        }
        //返回skip
        return skip;
    }
}

loadBeanDefinitionsForConfigurationClass加载注册beean定义

  通过reader加载、注册此configClasses中的bean定义,主要有一下4个加载的逻辑:

如果当前配置类是被引入的,通过@Import注解、处理内部类等方式找到的configClass,都算作被引入的。那么解析注册配置类本身成为AnnotatedGenericBeanDefinition类型的bean定义,并且注册到注册表中。在这里,就会对非静态内部配置类进行注册。
解析@Bean方法成为ConfigurationClassBeanDefinition类型的bean定义,并且注册到注册表中。
加载、解析@ImportedResource注解引入的XML配置文件中的bean定义到注册表中。核心还是BeanDefinitionReader.loadBeanDefinitions方法加载resource资源,解析、注册bean定义,
对于@Import注解引入的ImportBeanDefinitionRegistrar类型的对象的registerBeanDefinitions方法进行统一回调。该方法可用于自定义的注册、修改bean定义,因为它将注册表作为参数。

/**
 * ConfigurationClassBeanDefinitionReader的方法
 * <p>
 * 读取特定的ConfigurationClass配置类,注册该类本身及其所有@Bean方法的 bean 定义
 */
private void loadBeanDefinitionsForConfigurationClass(
        ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
    //如果trackedConditionEvaluator的shouldSkip方法返回true,即应该跳过
    if (trackedConditionEvaluator.shouldSkip(configClass)) {
        //获取beanName
        String beanName = configClass.getBeanName();
        //如果存在beanName,并且注册表中已经包含了该beanName的bean定义
        if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
            /*
             * 从注册表中移除该beanName的bean定义
             * 因此,此前加入进来的配置类的bean定义将可能被移除
             */
            this.registry.removeBeanDefinition(beanName);
        }
        //移除importRegistry即importStack中的缓存
        this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
        return;
    }
    //如果当前配置类是被引入的,通过@Import注解、处理内部类等方式找到的configClass,都算作被引入的
    if (configClass.isImported()) {
        /*
         * 1 解析注册配置类本身成为AnnotatedGenericBeanDefinition类型的bean定义,并且注册到注册表中。
         * 在这里,就会对非静态内部配置类进行注册。
         */
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }
    //获取全部的@Bean方法,遍历
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        /*
         * 2 解析@Bean方法成为ConfigurationClassBeanDefinition类型的bean定义,并且注册到注册表中。
         */
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }
    /*
     * 3 加载、解析@ImportedResource注解引入的XML配置文件中的bean定义到注册表中。
     * 核心还是BeanDefinitionReader的loadBeanDefinitions方法加载resource资源,解析、注册bean定义
     * 这个方法我们在"IoC容器初始化(2)"的文章中就详细讲过了
     */
    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    /*
     * 4 @Import注解引入的ImportBeanDefinitionRegistrar类型的对象的registerBeanDefinitions方法的回调。
     * 该方法可用于自定义的注册、修改bean定义,因为它将注册表作为参数
     */
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

registerBeanDefinitionForImportedConfigurationClass注册配置类本身

  如果当前配置类是被引入的,此前讲过,通过@Import注解、处理内部类等方式找到的configClass,都算作被引入的,那么该方法将配置类本身注册为 bean 定义,这里就是对@Import普通类和非静态内部类的beean定义进行注册的地方。
  将被解析为AnnotatedGenericBeanDefinition类型的bean定义,采用的beanName生成器是FullyQualifiedAnnotationBeanNameGenerator,在没找到beanName而主动生成的时候,生成的逻辑仅仅是将了类的全路径名作为beanName,相比于父类AnnotationBeanNameGenerator更加简单。
  注册的bean定义是和XML标签的解析一样是采用registerBeanDefinition方法,就是向注册表中添加的三个缓存beanDefinitionMap、beanDefinitionNames、aliasMap,这属于容器初始化的核心操作。

/**
 * ConfigurationClassBeanDefinitionReader的方法
 * <p>
 * 将配置类本身注册为 bean 定义,这里就是对非静态内部配置类进行注册的地方
 */
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
    AnnotationMetadata metadata = configClass.getMetadata();
    //创建AnnotatedGenericBeanDefinition类型的bean定义
    AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);

    ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
    configBeanDef.setScope(scopeMetadata.getScopeName());
    //查找或者生成beanName,采用的生成器是FullyQualifiedAnnotationBeanNameGenerator
    //它继承了AnnotationBeanNameGenerator,区别就在于如果没指定beanName那么自己的beanName生成规则是直接以全路径类名作为beanName
    String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
    //处理类上的其他通用注解:@Lazy, @Primary, @DependsOn, @Role, @Description
    AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
    //封装成为BeanDefinitionHolder对象
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
    //根据proxyMode属性的值,判断是否需要创建scope代理,一般都是不需要的
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    //调用registerBeanDefinition方法注册BeanDefinition到注册表的缓存中,该方法此前已经讲过了
    this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
    //设置beanName
    configClass.setBeanName(configBeanName);

    if (logger.isTraceEnabled()) {
        logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
    }
}

/**
 * FullyQualifiedAnnotationBeanNameGenerator类,用于查找和生成beanName
 * 重写了Spring生成beanName0的逻辑
 */
public class FullyQualifiedAnnotationBeanNameGenerator extends AnnotationBeanNameGenerator {

    /**
     * 重写了Spring生成beanName0的逻辑
     * 相比于父类AnnotationBeanNameGenerator更加简单,直接是将全路径类名注解作为beanName
     */
    @Override
    protected String buildDefaultBeanName(BeanDefinition definition) {
        String beanClassName = definition.getBeanClassName();
        Assert.state(beanClassName != null, "No bean class name set");
        return beanClassName;
    }

}

loadBeanDefinitionsForBeanMethod从@Bean方法加载bean定义

  @Bean方法对应的bean定义将被封装成为ConfigurationClassBeanDefinition类型,如果设置了name属性,那么将第一个值作为beanName,其他的值作为别名,否则直接将方法名作为beanName。
  如果在注册当前@Bean方法的bean定义时发现注册表中存在同名的的bean定义,那么可能会覆盖此前的bean定义或者保留此前的bean定义而不注册当前bean定义(具体在isOverriddenByExistingDefinition方法中)。
  @Bean方法的bean定义的注册和XML标签的解析一样是采用registerBeanDefinition方法,就是向注册表中添加的三个缓存beanDefinitionMap、beanDefinitionNames、aliasMap,这属于容器初始化的核心操作。
  可以看到,@Bean方法对应的ConfigurationClassBeanDefinition,设置了FactoryMethodName属性,也就是说,这里的@Bean方法均被解析为工厂方法,那么在IoC容器初始化的createBeanInstance创建bean实例阶段,将会通过工厂方法创建bean实例,即调用instantiateUsingFactoryMethod方法获取实例。

/**
 * ConfigurationClassBeanDefinitionReader的属性
 * 条件评估器,处理类或者方法上的@Conditional注解
 */
private final ConditionEvaluator conditionEvaluator;
/**
 * ConfigurationClass的属性
 * 当前配置类跳过的方法
 */
final Set<String> skippedBeanMethods = new HashSet<>();

/**
 1. ConfigurationClassBeanDefinitionReader的方法
 2. <p>
 3. 根据给定的BeanMethod解析为bean定义像注册表中注册
 4.  5. @param beanMethod 表示一个@Bean方法
 */
@SuppressWarnings("deprecation")  // for RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
    //获取方法所属的类
    ConfigurationClass configClass = beanMethod.getConfigurationClass();
    MethodMetadata metadata = beanMethod.getMetadata();
    //获取方法名
    String methodName = metadata.getMethodName();
    /*
     * 处理方法上的@Conditional注解,判断是否应该跳过此方法的处理
     * 这里的metadata就是方法元数据,MethodMetadata
     */
    //如果shouldSkip返回true,即当前@Bean的方法应该跳过解析,这里的phase生效的阶段参数为REGISTER_BEAN
    if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
        //那么加入到当前配置类的skippedBeanMethods缓存中
        configClass.skippedBeanMethods.add(methodName);
        return;
    }
    //如果此前就解析了该方法,并且应该跳过,那么直接返回
    if (configClass.skippedBeanMethods.contains(methodName)) {
        return;
    }

    //获取@Bean注解的属性集合
    AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
    Assert.state(bean != null, "No @Bean annotation attributes");
    /*
     * 考虑名字和别名
     */
    //获取name属性集合
    List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
    /*
     * 获取beanName。如果设置了name属性,那么将第一个值作为beanName,其他的值作为别名,否则直接将方法名作为beanName
     */
    String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
    for (String alias : names) {
        /*
         * 注册别名映射
         * 将是将别名alias和名字beanName的映射注册到SimpleAliasRegistry注册表的aliasMap缓存汇总
         */
        this.registry.registerAlias(beanName, alias);
    }

    /*
     * 校验是否存在同名的bean定义,以及是否允许同名的bean定义覆盖
     */
    if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
        //如果返回true,并且如果beanName就等于当前bean方法所属的类的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!");
        }
        //如果返回true,直接返回,当前bean方法不再解析
        return;
    }
    //新建一个ConfigurationClassBeanDefinition类型的bean定义,从这里可知@Bean方法的bean定义的类型
    ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
    beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
    //如果当前bean方法是静态的
    if (metadata.isStatic()) {
        //看作静态工厂方法
        // static @Bean method
        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);
    //处理方法上的其他通用注解:@Lazy, @Primary, @DependsOn, @Role, @Description
    AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
    //获取autowire属性,默认Autowire.NO,即不自动注入
    Autowire autowire = bean.getEnum("autowire");
    //设置自动注入模式
    if (autowire.isAutowire()) {
        beanDef.setAutowireMode(autowire.value());
    }
    //设置autowireCandidate属性,默认tue
    boolean autowireCandidate = bean.getBoolean("autowireCandidate");
    if (!autowireCandidate) {
        beanDef.setAutowireCandidate(false);
    }
    //设置initMethodName属性
    String initMethodName = bean.getString("initMethod");
    if (StringUtils.hasText(initMethodName)) {
        beanDef.setInitMethodName(initMethodName);
    }
    //设置destroyMethod属性
    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;
        }
    }

    //如有必要,将原始 bean 定义替换为代理目标定义
    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);
    }

    if (logger.isTraceEnabled()) {
        logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
                configClass.getMetadata().getClassName(), beanName));
    }
    //调用registerBeanDefinition方法注册BeanDefinition到注册表的缓存中,该方法此前已经讲过了
    this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

isOverriddenByExistingDefinition是否支持现有bean定义的覆盖

  使用获取或者生成的beanName,在注册表中查找同名的bean定义并校验,对于@Bean的bean定义来说可能会覆盖其他同名bean定义或者被其他同名bean定义:

如果注册表中不包含该beanName的bean定义,那么返回false,可以继续向后解析该bean方法。后面的步骤都表示注册表中包含该beanName的bean定义;
如果现有的 bean 定义也是从通过@Bean方法创建的,那么允许bean 方法重写:
如果这两个@Bean方法不属于同一个类。那么返回false,当前@Bean方法将覆盖这个同名bean定义。
如果这两个@Bean方法属于同一个类,并且这两个@Bean方法的方法名一致,即存在重载方法情况,那么返回true,将保留现有的bean定义,不再继续向后解析该@Bean方法。
从Spring 4.2开始,由组件扫描(基于组件注解)产生的bean定义可以被@Bean方法静默地覆盖:
如果该同名bean定义是通过组件扫描注解产生的(通过组件扫描注解产生的bean定义类型就是ScannedGenericBeanDefinition)。那么返回false,当前bean方法将覆盖这个同名bean定义。
现有 bean 定义的role已标记为框架生成的 bean 吗?如果是,这允许当前 bean 方法重写它,因为它是应用程序级,返回false,当前bean方法将覆盖这个同名bean定义。
如果现有 bean 定义是通过XML产生的,并且不允许同名的BeanDefinition 覆盖(默认允许)那么因为存在同名的bean定义而抛出异常"@Bean definition illegally overridden by existing bean definition: "。
最后的返回true,表示不存在同名的bean定义或者允许同名bean定义覆盖。

/**
 * ConfigurationClassBeanDefinitionReader的方法
 * 
 * 是否已存在同名bean定义或者允许现有的bean定义被覆盖
 */
protected boolean isOverriddenByExistingDefinition(BeanMethod beanMethod, String beanName) {
    //如果注册表中不包含该beanName的bean定义
    if (!this.registry.containsBeanDefinition(beanName)) {
        //直接返回false
        return false;
    }
    //到这里,表示注册表中包含该beanName的bean定义
    BeanDefinition existingBeanDef = this.registry.getBeanDefinition(beanName);


    /*
     * 如果现有的 bean 定义也是从通过bean方法创建的,那么允许bean 方法重写
     */
    if (existingBeanDef instanceof ConfigurationClassBeanDefinition) {
        ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef;
        //如果这两个bean方法属于同一个类
        if (ccbd.getMetadata().getClassName().equals(
                beanMethod.getConfigurationClass().getMetadata().getClassName())) {
            //如果这两个bean方法的方法名一致,即重载方法情况,那么返回true,保留现有的 bean 定义
            if (ccbd.getFactoryMethodMetadata().getMethodName().equals(ccbd.getFactoryMethodName())) {
                ccbd.setNonUniqueFactoryMethodName(ccbd.getFactoryMethodMetadata().getMethodName());
            }
            return true;
        }
        //否则,返回false,因为这两个bean方法不属于同一个类,当前bean方法将覆盖这个同名bean定义
        else {

            return false;
        }
    }
    /*
     * 从Spring 4.2开始,由组件扫描产生的bean定义可以被@Bean方法静默地覆盖
     * 如果该同名bean定义是通过组件扫描注解产生的(通过组件扫描主角儿产生的bean定义类型就是ScannedGenericBeanDefinition)
     * 那么返回false,当前bean方法将覆盖这个同名bean定义
     */
    if (existingBeanDef instanceof ScannedGenericBeanDefinition) {
        //返回false,当前bean方法将覆盖这个同名bean定义
        return false;
    }
    /*
     * 现有 bean 定义的role已标记为框架生成的 bean 吗?如果是,这允许当前 bean 方法重写它,因为它是应用程序级
     * 那么返回false,当前bean方法将覆盖这个同名bean定义
     */
    if (existingBeanDef.getRole() > BeanDefinition.ROLE_APPLICATION) {
        return false;
    }
    /*
     * 如果现有 bean 定义是通过XML产生的,并且不允许同名的BeanDefinition 覆盖(默认允许)
     * 那么因为存在同名的bean定义而抛出异常"@Bean definition illegally overridden by existing bean definition: "
     */
    if (this.registry instanceof DefaultListableBeanFactory &&
            !((DefaultListableBeanFactory) this.registry).isAllowBeanDefinitionOverriding()) {
        throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
                beanName, "@Bean definition illegally overridden by existing bean definition: " + existingBeanDef);
    }
    if (logger.isDebugEnabled()) {
        logger.debug(String.format("Skipping bean definition for %s: a definition for bean '%s' " +
                        "already exists. This top-level bean definition is considered as an override.",
                beanMethod, beanName));
    }
    //返回true
    return true;
}

loadBeanDefinitionsFromImportedResources从@ImportedResource加载bean定义

  加载、解析@ImportedResource注解引入的XML配置文件中的bean定义到注册表中。其内部最终还是调用BeanDefinitionReader的loadBeanDefinitions方法,加载resource资源,解析、注册bean定义。

/**
 * ConfigurationClassBeanDefinitionReader的方法
 * <p>
 * 加载、解析@ImportedResource注解引入的XML配置文件中的bean定义到注册表中。
 *
 * @param importedResources 解析后的资源路径字符串
 */
private void loadBeanDefinitionsFromImportedResources(
        Map<String, Class<? extends BeanDefinitionReader>> importedResources) {
    //bean定义读取器的缓存
    Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();
    /*循环加载*/
    importedResources.forEach((resource, readerClass) -> {
        // Default reader selection necessary?
        if (BeanDefinitionReader.class == readerClass) {
            //支持 Groovy 语言
            if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
                // When clearly asking for Groovy, that's what they'll get...
                readerClass = GroovyBeanDefinitionReader.class;
            } else {
                // Primarily ".xml" files but for any other extension as well
                readerClass = XmlBeanDefinitionReader.class;
            }
        }

        BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
        //如果reader为null,那么新建reader
        if (reader == null) {
            try {
                // Instantiate the specified BeanDefinitionReader
                reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
                // Delegate the current ResourceLoader to it if possible
                if (reader instanceof AbstractBeanDefinitionReader) {
                    AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);
                    abdr.setResourceLoader(this.resourceLoader);
                    abdr.setEnvironment(this.environment);
                }
                readerInstanceCache.put(readerClass, reader);
            } catch (Throwable ex) {
                throw new IllegalStateException(
                        "Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
            }
        }

        //最终调用reader的loadBeanDefinitions方法加载resource资源,解析、注册bean定义
        reader.loadBeanDefinitions(resource);
    });
}

loadBeanDefinitionsFromRegistrars从@Import加载bean定义

  该方法主要就是对于此前在processImports方法中的ImportBeanDefinitionRegistrar类型的引入类对象的registerBeanDefinitions方法的统一回调。

/**
 * ConfigurationClassBeanDefinitionReader的方法
 * <p>
 * 注册@Import注解引入的bean定义到注册表中
 *
 * @param registrars importBeanDefinitionRegistrars缓存
 */
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
    //循环importBeanDefinitionRegistrars缓存map,回调每一个ImportBeanDefinitionRegistrar对象的三个参数的registerBeanDefinitions方法
    registrars.forEach((registrar, metadata) ->
            registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}

postProcessBeanFactory

  postProcessBeanFactory方法同样在IoC容器初始化的invokeBeanFactoryPostProcessors步骤中被自动回调,当然调用时机晚于postProcessBeanDefinitionRegistry,并且逻辑也更加简单。
  在此前我们已经解析了全部的配置类,该方法就是对于被@Configuration及其派生注解标注的配置类生成CGLIB代理对象,主要目的是对@Bean方法进行代理增强,最后还会添加一个ImportAwareBeanPostProcessor类型的后处理器。

/**
 * ConfigurationClassPostProcessor的方法
 * <p>
 * 对于被@Configuration注解标注的配置类生成CGLIB代理对象,主要目的是在对bean方法的调用进行代理增强
 * 最后还会添加一个ImportAwareBeanPostProcessor类型的后处理器
 */
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    //一致性哈希值的校验,类似于postProcessBeanDefinitionRegistry方法
    int factoryId = System.identityHashCode(beanFactory);
    //如果factoriesPostProcessed缓存包含了该factoryId值,那么说明此前该beanFactory已被该ConfigurationClassPostProcessor处理过了
    //Spring不允许同一个ConfigurationClassPostProcessor重复处理同一个beanFactory,直接抛出异常
    if (this.factoriesPostProcessed.contains(factoryId)) {
        throw new IllegalStateException(
                "postProcessBeanFactory already called on this post-processor against " + beanFactory);
    }
    //当前beanFactory的factoryId加入factoriesPostProcessed缓存
    this.factoriesPostProcessed.add(factoryId);
    //如果registriesPostProcessed缓存不包含该factoryId,那么先调用processConfigBeanDefinitions处理所有的配置类
    if (!this.registriesPostProcessed.contains(factoryId)) {
        // BeanDefinitionRegistryPostProcessor hook apparently not supported...
        // Simply call processConfigurationClasses lazily at this point then.
        processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
    }
    /*
     * 1 增强配置类
     */
    enhanceConfigurationClasses(beanFactory);
    /*
     * 2 添加ImportAwareBeanPostProcessor类型的BeanPostProcessor后处理器
     */
    beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

enhanceConfigurationClasses增强配置类

  查找全部被@Configuration注解及其派生注解标注的proxyBeanMethods属性的值为true(默认就是true)的配置类,也就是具有"full"属性的配置类,并通过ConfigurationClassEnhancer进行代理增强。
  postProcessBeanDefinitionRegistry方法的checkConfigurationClassCandidate方法用于检测配置类并设置相应的属性,被@Configuration注解以及派生注解标注的配置类,就会被标记为"full",其他配置类则标记为“lite”。在该方法中终于用到了这个属性。
  对于full模式的Configuration,将会通过ConfigurationClassEnhancer配置类增强器生成CGLIB子类,并设置给当前bean定义的beanClass属性,那么后面在创建该配置类的实例时就会创建代理类的实例!
  创建代理子类的核心方法是enhancer.enhance方法!

public static final String CONFIGURATION_CLASS_ATTRIBUTE = Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");

/**
 * ConfigurationClassPostProcessor的方法
 * <p>
 * 查找全部被@Configuration注解标注的配置类,也就是具有"full"属性的配置类,并通过ConfigurationClassEnhancer进行代理增强
 */
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    //需要进行代理增强的配置类集合
    Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
    //遍历全部的BeanDefinition
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
        //获取CONFIGURATION_CLASS_ATTRIBUTE属性的值
        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) {
            // Configuration class (full or lite) or a configuration-derived @Bean method
            // -> resolve bean class at this point...
            AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
            if (!abd.hasBeanClass()) {
                try {
                    abd.resolveBeanClass(this.beanClassLoader);
                } catch (Throwable ex) {
                    throw new IllegalStateException(
                            "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
                }
            }
        }
        //校验是否是full模式的Configuration
        if (ConfigurationClassUtils.CONFIGURATION_CLASS_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");
            } else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
                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'.");
            }
            //当前full模式的Configuration 的beanName和bean定义都存入configBeanDefs集合
            configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
        }
    }
    //如果configBeanDefs是空集,那么直接返回,不需要增强
    if (configBeanDefs.isEmpty()) {
        // nothing to enhance -> return immediately
        return;
    }
    //新建一个配置类增强器,通过生成CGLIB子类来增强配置类
    ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
        AbstractBeanDefinition beanDef = entry.getValue();
        // If a @Configuration class gets proxied, always proxy the target class
        //新设置一个属性,如果@Configuration已代理,那么始终代理目标类
        beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
        // Set enhanced subclass of the user-specified bean class
        Class<?> configClass = beanDef.getBeanClass();
        //设置用户指定的 bean 类的CGLIB 增强子类
        Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
        if (configClass != enhancedClass) {
            if (logger.isTraceEnabled()) {
                logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
                        "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
            }
            //设置class为增强类的class,后续创建该配置类的实例时就会创建代理类的实例
            beanDef.setBeanClass(enhancedClass);
        }
    }
}

enhance增强

  被创建的CGLIB子类将继承当前目标配置类,并且实现EnhancedConfiguration接口(EnhancedConfiguration也实现了BeanFactoryAware接口)。
  被创建的CGLIB子类包括两个回调过滤器,一个是BeanMethodInterceptor拦截器,将会拦截配置类中的@Bean方法,另一个是BeanFactoryAwareMethodInterceptor拦截器,将会拦截setBeanFactory方法。所谓的“增强”,实际上就是对这两种方法的增强,而增强的具体实现就是通过这两个拦截器实现的!

/**
 * ConfigurationClassEnhancer的方法
 * <p>
 * 加载指定的类并生成其配备容器感知回调的 CGLIB 子类
 *
 * @return 被增强的子类
 */
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
    //如果目标类型已经是EnhancedConfiguration的类型,那么直接返回
    if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("Ignoring request to enhance %s as it has " +
                            "already been enhanced. This usually indicates that more than one " +
                            "ConfigurationClassPostProcessor has been registered (e.g. via " +
                            "<context:annotation-config>). This is harmless, but you may " +
                            "want check your configuration and remove one CCPP if possible",
                    configClass.getName()));
        }
        return configClass;
    }
    //通过一个Enhancer创建子类class
    Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
    if (logger.isTraceEnabled()) {
        logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
                configClass.getName(), enhancedClass.getName()));
    }
    return enhancedClass;
}


//---------ConfigurationClassEnhancer的相关属性-------------

/**
 * 要使用的回调拦截器
 */
private static final Callback[] CALLBACKS = new Callback[]{
        //支持@Bean方法的回调拦截
        new BeanMethodInterceptor(),
        //支持BeanFactoryAware的setBeanFactory方法的回调拦截
        new BeanFactoryAwareMethodInterceptor(),
        NoOp.INSTANCE
};
/**
 * 条件回调筛选器,默认支持@Bean方法的回调拦截和BeanFactoryAware的setBeanFactory方法的回调拦截
 */
private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);

/**
 * ConfigurationClassEnhancer的方法
 * <p>
 * 创建CGLIB增强器实例
 */
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
    Enhancer enhancer = new Enhancer();
    //设置继承的父类为目标类型
    enhancer.setSuperclass(configSuperClass);
    //设置实现的接口为EnhancedConfiguration,并且EnhancedConfiguration也实现了BeanFactoryAware接口
    enhancer.setInterfaces(new Class<?>[]{EnhancedConfiguration.class});
    enhancer.setUseFactory(false);
    //设置类名命名策略
    enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    //设置用于从此生成器创建字节码的策略
    enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
    //回调过滤器
    enhancer.setCallbackFilter(CALLBACK_FILTER);
    //设置回调类型,默认BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor
    enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
    return enhancer;
}

BeanMethodInterceptor拦截器

  BeanMethodInterceptor该拦截器实现了cglib的MethodInterceptor(区别于Spring的MethodInterceptor),用于拦截当前配置类内部的任何@Bean方法的调用以及@Bean方法之间的调用,以确保正确处理 bean 语义。
   简单的说,对于被@Configuration注解及其派生注解标注的proxyBeanMethods属性的值为true(默认就是true)的配置类,内部的单例@Bean方法仅仅会被调用一次,用于创建对象,后续如果存在任何@Bean方法之间的调用,或者外部对象对@Bean方法的调用(这要求该对象交给Spring容器管理),都会是从容器中直接查找已创建的对象返回,不会再调用@Bean方法,能够保证是同一个实例,即都指向IoC内的单例。

  当@Bean方法被调用的时候,就会走intercept方法:

调用getBeanFactory方法获取beanFactory,实际上代理类生成了一个"$$beanFactory"属性,用于存放beanFactory。
该方法会默认将方法名作为beanName,,如果指定了@Bean注解的name属性,那么将会取第一个值作为beanName。
检查当前beanName对应的bean实例或者定义存在,并且是FactoryBean类型,第一次调用的时候应该是不存在的。如果存在就返回一个FactoryBean代理对象。
isCurrentlyInvokedFactoryMethod方法用于检查给定方法是否对应于容器当前调用的方法,仅比较方法名称和参数类型。也就是说,如果@Bean方法是Spring自动调用的,比如用于创建对象,那么返回true,如果在其他@Bean方法中被调用,那么返回false。
如果是Spring自动调用的该@Bean方法,那么调用invokeSuper方法,实际上就是调用当前@Bean方法本身,用于创建bean实例,没有任何增强,返回对应的结果。
如果当前@Bean方法是在其他@Bean方法中被调用的。那么调用resolveBeanReference尝试直接从容器中获取给定BeanName的对象,如果容器中有,就直接返回,该@Bean方法后续不再被调用;如果没有,那么创建,该@Bean方法被调用一次,后续不再被调用。其核心就是beanFactory.getBean方法。

/**
 * BeanMethodInterceptor的方法
 * <p>
 * 通过检查提供的 BeanFactory 是否已存在此 Bean 对象,来增强此@Bean方法
 *
 * @param enhancedConfigInstance 当前代理子类对象
 * @param beanMethod             调用方法
 * @param beanMethodArgs         方法参数
 * @param cglibMethodProxy       方法代理对象
 */
@Override
@Nullable
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
                        MethodProxy cglibMethodProxy) throws Throwable {
    //调用getBeanFactory方法获取beanFactory,实际上代理类生成了一个"$$beanFactory"属性,用于存放beanFactory
    ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
    //获取当前@Bean方法的beanName,默认就是方法名,如果指定了@Bean注解的name属性,那么将会取第一个值作为beanName
    String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);

    //是否是作用域代理,一般都不是
    if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
        String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
        if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
            beanName = scopedBeanName;
        }
    }


    //如果要处理 bean 方法间引用的情况,我们必须显式检查容器中已有缓存的实例。

    //检查当前beanName对应的bean定义存在并且是FactoryBean类型,第一次调用的时候应该是不存在的
    if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
            factoryContainsBean(beanFactory, beanName)) {
        //获取factoryBean实例本身
        Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
        //创建一个FactoryBean的增强类来拦截getObject方法
        if (factoryBean instanceof ScopedProxyFactoryBean) {
            // Scoped proxy factory beans are a special case and should not be further proxied
        } else {
            // 这里将会选择合适的代理方式,JDK的代理或者CGLIB的代理
            return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
        }
    }
    /*
     * 检查给定方法是否对应于容器当前调用的方法,仅比较方法名称和参数类型
     * 也就是说,如果@Bean方法是Spring自动调用的,比如用于创建对象,那么返回true
     * 如果在其他@Bean方法中被调用,那么返回false
     */
    if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
        // The factory is calling the bean method in order to instantiate and register the bean
        // (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
        // create the bean instance.
        if (logger.isInfoEnabled() &&
                BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
            logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
                            "assignable to Spring's BeanFactoryPostProcessor interface. This will " +
                            "result in a failure to process annotations such as @Autowired, " +
                            "@Resource and @PostConstruct within the method's declaring " +
                            "@Configuration class. Add the 'static' modifier to this method to avoid " +
                            "these container lifecycle issues; see @Bean javadoc for complete details.",
                    beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
        }
        //调用invokeSuper方法,实际上就是调用当前@Bean方法本身,没有任何增强,返回对应的结果
        return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
    }
    /*
     * 到这里,表示当前@Bean方法是在其他@Bean方法中被调用的
     * 那么直接从容器中获取给定BeanName的对象,如果容器中有,就直接返回,该@Bean方法后续不再被调用
     * 如果没有,那么创建,该@Bean方法被调用一次,后续不再被调用
     */
    return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}

/**
 * 检查beanFactory中是否包含指定beanName的bean实例或者bean定义
 */
private boolean factoryContainsBean(ConfigurableBeanFactory beanFactory, String beanName) {
    return (beanFactory.containsBean(beanName) && !beanFactory.isCurrentlyInCreation(beanName));
}

/**
 * 检查给定方法是否对应于容器当前调用的方法,仅比较方法名称和参数类型
 * 也就是说,如果@Bean方法是Spring自动调用的,比如用于创建对象,那么返回true
 * 如果在其他@Bean方法中被调用,那么返回false
 */
private boolean isCurrentlyInvokedFactoryMethod(Method method) {
    Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
    return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
            Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}

resolveBeanReference解析bean引用

  如果当前@Bean方法是在其他@Bean方法中被调用,或者是外部对象对@Bean方法的调用(这要求该对象交给Spring容器管理),那么直接从容器中获取给定BeanName的对象,如果容器中有,就直接返回,该@Bean方法后续不再被调用。如果没有,那么创建,该@Bean方法被调用一次,后续不再被调用。
  核心方法就是IoC容器初始化的finishBeanFactoryInitialization阶段beanFactory.getBean方法(该方法我们在),如果有缓存,就从缓存取,没有就创建。创建的方法,在getBean方法内部的createBeanInstance方法中,将会通过工厂方法创建bean实例,即调用instantiateUsingFactoryMethod方法获取实例。IoC容器初始化我们在前面的文章就讲过了。
  如果@Bean方法之间存在互相调用,可以是间接的通过其他外部对象(这要求该对象交给Spring容器管理)调用,那么表示它们存在依赖关系,将会通过registerDependentBean方法注册到容器中,如果仅仅是外部对象(这要求该对象交给Spring容器管理)调用@Bean方法,那么不会注册依赖关系。

/**
 * BeanMethodInterceptor的方法
 * <p>
 * 如果当前@Bean方法是在其他@Bean方法中被调用,或者是外部对象对@Bean方法的调用(这要求该对象交给Spring容器管理)
 * 那么直接从容器中获取给定BeanName的对象,如果容器中有,就直接返回,该@Bean方法后续不再被调用
 * 如果没有,那么创建,该@Bean方法被调用一次,后续不再被调用
 * 核心就是beanFactory.getBean方法
 */
private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
                                    ConfigurableBeanFactory beanFactory, String beanName) {

    //当前bean是否在创建中
    boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
    try {
        if (alreadyInCreation) {
            //设置为非创建状态
            beanFactory.setCurrentlyInCreation(beanName, false);
        }
        //判断是否需要使用参数
        boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
        //如果需要使用参数并且当前beanName对应的bean是单例的
        if (useArgs && beanFactory.isSingleton(beanName)) {
            //如果有一个参数为null,那么useArgs设置为false,@Bean单例对象的参数不是可选的
            for (Object arg : beanMethodArgs) {
                if (arg == null) {
                    useArgs = false;
                    break;
                }
            }
        }
        //调用beanFactory.getBean方法获取bean实例,这一步就是从缓存中获取,如果没有,那么就创建,创建的时候就会调用那个该@Bean方法
        //如果有就直接返回,不再调用该@Bean方法
        Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
                beanFactory.getBean(beanName));
        //是否等于给定类型,一般都不相等,除了字符串类型
        if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
            //这里的equals是为了检测NullBean实例
            if (beanInstance.equals(null)) {
                if (logger.isDebugEnabled()) {
                    logger.debug(String.format("@Bean method %s.%s called as bean reference " +
                                    "for type [%s] returned null bean; resolving to null value.",
                            beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
                            beanMethod.getReturnType().getName()));
                }
                //如果是NullBean,那么设置为null
                beanInstance = null;
            } else {
                String msg = String.format("@Bean method %s.%s called as bean reference " +
                                "for type [%s] but overridden by non-compatible bean instance of type [%s].",
                        beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
                        beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
                try {
                    BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
                    msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
                } catch (NoSuchBeanDefinitionException ex) {
                    // Ignore - simply no detailed message then.
                }
                throw new IllegalStateException(msg);
            }
        }
        //获取当前最外层正在被调用的@Bean方法,也就是直接或者见解调用该@Bean方法的@Bean方法,因此可能为null
        Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
        if (currentlyInvoked != null) {
            //获取外部@Bean方法的beanName
            String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
            //注册外部@Bean方法和内部@Bean方法的依赖关系
            beanFactory.registerDependentBean(beanName, outerBeanName);
        }
        return beanInstance;
    } finally {
        //重新设置为正在创建中
        if (alreadyInCreation) {
            beanFactory.setCurrentlyInCreation(beanName, true);
        }
    }
}

BeanFactoryAwareMethodInterceptor拦截器

  BeanFactoryAwareMethodInterceptor拦截器用于拦截当前被@Configuration注解及其派生注解标注的配置类内部的setBeanFactory方法的调用在。
  它的intercept方法就很简单了,就是为CGLIB子类对象的"$$beanFactory"属性赋值为当前的beanFactory实例,在后面拦截@Bean方法的时候会用到(前面见识过了)。

/**
 * BeanFactoryAwareMethodInterceptor的方法
 * <p>
 * 拦截BeanFactoryAware的setBeanFactory方法回调,为"$$beanFactory"属性赋值
 * 这里的拦截早于@Bean方法的拦截,在创建对象之后就马上调用了该方法
 */
@Override
@Nullable
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    //获取代理对象的"$$beanFactory"字段
    Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
    Assert.state(field != null, "Unable to find generated BeanFactory field");
    //设置置为第一个参数,也就是注入的beanFactory实例,在后面拦截@Bean方法的时候会用到
    field.set(obj, args[0]);

    //如果实际代理的目标类型还实现了BeanFactoryAware接口,那么还是调用其对应的setBeanFactory方法,否则直接退出
    if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
        return proxy.invokeSuper(obj, args);
    }
    return null;
}

ImportAwareBeanPostProcessor后处理器

  在postProcessBeanFactory方法的最后,注册了一个ImportAwareBeanPostProcessor类型的后处理器,这个后处理器就是为了支持配置类代理类对象的创建!
  postProcessProperties方法在createBeanInstance方法创建bean实例之后, initializeBean初始化bean之前的populateBean装配bean的方法中被调用,就是用于对于EnhanceConfiguration类型的代理对象调用setBeanFactory方法设置beanFactory的属性值的。
  postProcessBeforeInitialization方法则是在initializeBean初始化bean的时候被调用,用于ImportAware类型的bean实例的setImportMetadata方法回调,获取引入当前类的类元数据的最后一个(当前类就是被@Import注解引入的普通类,引入类就是添加@Import注解的类),设置到setImportMetadata方法参数中。

/**
 * ConfigurationClassPostProcessor的属性
 */
private static final String IMPORT_REGISTRY_BEAN_NAME =
        ConfigurationClassPostProcessor.class.getName() + ".importRegistry";


/**
 1. ImportAwareBeanPostProcessor类,位于ConfigurationClassPostProcessor内部
 */
private static class ImportAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {

    private final BeanFactory beanFactory;

    public ImportAwareBeanPostProcessor(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    /**
     * 为EnhancedConfiguration代理对象调用setBeanFactory方法设置beanFactory的属性值
     */
    @Override
    public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) {
        //对于EnhancedConfiguration类型的代理对象注入beanFactory实例
        if (bean instanceof EnhancedConfiguration) {
            ((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
        }
        return pvs;
    }

    /**
     * 用于ImportAware的setImportMetadata方法回调,设置importMetadata元数据
     * 主要是支持@Import注解引入的类
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        //如果是ImportAware类型
        if (bean instanceof ImportAware) {
            //获取IMPORT_REGISTRY_BEAN_NAME的bean实例,在前面的processConfigBeanDefinitions方法最后就注册了该名字的bean实例
            ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
            //获取引入当前类的类元数据的最后一个,当前类就是被@Import注解引入的普通类,引入类就是添加@Import注解的类
            AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
            if (importingClass != null) {
                //设置到setImportMetadata方法参数中
                ((ImportAware) bean).setImportMetadata(importingClass);
            }
        }
        return bean;
    }
}

ConfigurationClassPostProcessor总结

  我们前面学习了ConfigurationClassPostProcessor的两大方法postProcessBeanDefinitionRegistry和postProcessBeanFactory,现在我们终于知道这个后处理器的重要性了吧?现在我们来简单总结一下:

postProcessBeanDefinitionRegistry方法:
先被回调,用于整体解析配置类,注册bean定义。
如果具有@Configuration注解及其派生注解标注并且proxyBeanMethods属性的值为true(默认就是true),那么算作配置类,设置为full模式,如果具有@Bean,@Component,@ComponentScan,@Import,@ImportResource注解及其派生注解之一,那么同样算作配置类,设置为lite模式;这个模式将会在postProcessBeanFactory方法中用到。关于full和lite模式官方也有解释。
解析配置类的内部类以及各种注解:@Order 排序注解、@Conditional条件注解、@PropertySources以及@PropertySource属性源注解、@ComponentScans以及@ComponentScan组件扫描注解、@Import引入bean注解、@ImportResource配置文件注解、@Bean注解。主要目的是解析出其中的bean定义并且注册到容器中,核心方法就是paese方法和loadBeanDefinitions方法。
这里也是对于非静态内部类的bean定义进行注册的地方,具体方法就是registerBeanDefinitionForImportedConfigurationClass,默认beanName就是类的全路径名。此前容器初始化过程中所讲的doScan方法中并没有解析注册非静态内部类的bean定义。
postProcessBeanFactory方法:
后被回调,进一步处理配置类,对full模式配置类进行代理增强配置。
对于具有@Configuration注解及其派生注解标注的proxyBeanMethods属性的值为true(默认就是true)的配置类,将会设置CGLIB代理子类替换原来的beanClass,后面再创建bean实例的时候,实际上就会创建一个代理子类对象。
这里代理子类对象,继承了目标代理类,因此这要求配置类对象不能是final修饰的,并且还实现了EnhancedConfiguration接口,而EnhancedConfiguration也实现了BeanFactoryAware接口,将会自动回调setBeanFactory方法。
被创建的CGLIB子类包括两个回调过滤器,一个是BeanMethodInterceptor拦截器,将会拦截配置类中的@Bean方法,另一个是BeanFactoryAwareMethodInterceptor拦截器,将会拦截setBeanFactory方法。所谓的“增强”,实际上就是对这两种方法的增强,而增强的具体实现就是通过这两个拦截器实现的!
对于被@Configuration注解及其派生注解标注的proxyBeanMethods属性的值为true(默认就是true)的配置类,内部的单例@Bean方法仅仅会被调用一次,用于创建对象,后续如果存在任何@Bean方法之间的调用,或者外部对象对@Bean方法的调用(这要求该对象交给Spring容器管理),都会是从容器中直接查找已创建的对象返回,不会再调用@Bean方法,能够保证是同一个实例,即都指向IoC容器内的单例,这就是full模式配置类的好处之一,但缺点就是由于生成了代理对象,造成性能有所缺失。
对于被@Configuration注解及其派生注解标注的proxyBeanMethods属性的值为true(默认就是true)的配置类,它内部的@Bean方法,如果是static方法,则对于访问修饰符不作任何限制,因为不需要进行代理拦截,因此也没有上面的好处;如果不是static方法,就要求@Bean方法不能被private或者final修饰,因为这需要进行代理拦截。
最后会添加一个ImportAwareBeanPostProcessor后处理器,用于调用setBeanFactory和setImportMetadata方法设置相关属性。
这两个方法还有很多细节没总结出来,具体内容应该仔细看前面的源码。另外,里面的很多重要方法的源码也没讲解,比如environment.resolveRequiredPlaceholders(location)是怎么解析占位符的、loadBeanDefinitions(resource)是怎么加载资源路径字符串的、registry.registerBeanDefinition具体是怎么注册bean定义的……等等这些方法由于都是IoC容器初始化的核心方法,因此在此前IoC容器初始化的整体流程中就重点讲过了,要想掌握这些知识点,那还需要花费大量时间,大家可以看我此前的文章,总计约20万字的IoC初始化整体流程:Spring 5.x 源码。
实际上,前面的文章加上该文章内容都学习完毕,那么Spring IoC的重要源码才算基本学习完毕,后面我们将介绍其他部分的核心源码,比如Spring AOP、事务机制等。