• 欢迎访问 winrains 的个人网站!
  • 本网站主要从互联网整理和收集了与Java、网络安全、Linux等技术相关的文章,供学习和研究使用。如有侵权,请留言告知,谢谢!

Spring Boot源码分析(3):@Configuration注解的解析

Spring Boot winrains 来源:模范青蛙 12个月前 (11-05) 46次浏览

1. 简介

本篇文章是对上一篇文章Spring刷新应用上下文的补充说明,详细讲述了上一篇文章中的第五步(实例化并调用所有注册的beanFactory后置处理器)中Spring解析@Configuration注解的过程。
在Spring3.0之前的Spring核心框架中,我们启动一个Spring容器必须使用一个XML文件。而到了3.0之后的版本Spring为创建容器新增了一个入口类——AnnotationConfigApplicationContext。AnnotationConfigApplicationContext和过去的ClassPathXmlApplicationContext、FileSystemXmlApplicationContext等方法不同的是他不用再指定任何XML配置文件,而是可以通过指定类向容器添加Bean。
因此,从Spring3.0后,只要在配置类上加@Configuration注解就可以替换之前的xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。从使用的角度来说可以把他理解为XML配置中的<beans>标签,但是二者又有些细节的差异。在<beans>标签中除了使用<bean>声名Bean以外,还有各种<context>标签来扩展功能,比如<context:component-scan/>、<context:annotation-config />以及<import>等,这些扩展的功能并不是@Configuration注解的参数,而是通过其它注解来实现的如:@ComponentScan、@Import。

1.1 前提

使用@Configuration注解需满足以下要求

  1. @Configuration不可以是final类型;
  2. @Configuration不可以是匿名类;
  3. 嵌套的configuration必须是静态类。

1.2 声明

Spring对@Configuration注解类的解析最终是在ConfigurationClassPostProcessor类调用的processConfigBeanDefinitions方法中使用Spring的工具类ConfigurationClassParser来进行的。ConfigurationClassPostProcessor类是BeanFactoryPostProcessor的实现(看下图),BeanFactoryPostProcessor用于spring应用启动过程中@Configuration类的处理(发现和处理所有的配置类,注册其中的bean定义)。
http://image.winrains.cn/2019/11/20191105173925-20b9b.png

1.3 @Configuration源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    @AliasFor(annotation = Component.class)
    String value() default ""; //可以自定义Bean的名称
}

2 @Configuration类的解析

介绍
ConfigurationClassPostProcessor 位于 org.springframework.context.annotation 包中,这是一个 BeanDefinitionRegistryPostProcessor,隐含地也实现了接口BeanFactoryPostProcessor,用于spring 应用启动过程中 @Configuration 类的处理(发现和处理所有的配置类,注册其中的bean定义)。
引入时机

  • 非Springboot的Sping应用,当在配置文件中使用<context:annotation-config/>或者 <context:component-scan/>时,该BeanFactoryPostProcessor会被注册。
  • Springboot 应用中在ApplicationContext对象创建时,会在应用上下文类(参考AnnotationConfigServletWebServerApplicationContext/AnnotationConfigReactiveWebServerApplicationContext)的构造函数中创建AnnotatedBeanDefinitionReader对象时调用 AnnotationConfigUtils.registerAnnotationConfigProcessors() 注册这个BeanFactoryPostProcessor到容器。

调用时机
ConfigurationClassPostProcessor既实现了BeanDefinitionRegistryPostProcessor定义的方法postProcessBeanDefinitionRegistry,也实现了接口BeanFactoryPostProcessor定义的方法postProcessBeanFactory。
AbstractApplicationContext.refresh()方法执行时,在BeanFactory,也就是Spring容器被准备(prepare)和postProcess之后,AbstractApplicationContext的invokeBeanFactoryPostProcessors()方法被调用,这个方法用来执行所有容器中被作为bean注册的BeanFactoryPostProcessor,其中就包括对ConfigurationClassPostProcessor方法postProcessBeanDefinitionRegistry()以及postProcessBeanFactory()方法的调用。
调用过程
解析过程是在容器刷新方法中–refreshContext(context) –> refresh(context) –> ApplicationContext.refresh()
–> invokeBeanFactoryPostProcessor(beanFactory)(该方法在容器刷新专栏有详细讲解,就是调用了PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors方法)这个方法调用所有的BeanFactoryPostProcessor,同时也就启动了Configuration类的解析。此时的BeanFactory中已经加载了main class,以及内部定义的class。内部定义的class都是带internal的,这些并不是Configuration Class,解析程序会忽略这些类,最后只有SpringBoot的启动类(如:DemoApplication)会进行Configuration的解析处理。
这里之所有这样做的原因是上述方法执行时有可能注册新的BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor到容器,而这些新注册的BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor也需要在这个阶段执行。
注意事项

  • BeanDefinitionRegistryPostProcessor可能会注册另外一个BeanDefinitionRegistryPostProcessor。
  • 一个非BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor可能会注册另外一个BeanFactoryPostProcessor。
  • 一个非BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor不会注册另外一个BeanDefinitionRegistryPostProcessor(注册了但是不会被执行)。

因为配置类中定义的每个bean定义方法都必须要赶在其它BeanFactoryPostProcessor应用前,所以完成bean定义注册任务的ConfigurationClassPostProcessor 被设计为拥有最高执行优先级Ordered.HIGHEST_PRECEDENCE。

2.1 开始看代码

重提上一篇文章Spring 刷新应用上下文中的invokeBeanFactoryPostProcessors方法,用以引出下文。

//实例化并调用所有注册的beanFactory后置处理器
public static void invokeBeanFactoryPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    Set<String> processedBeans = new HashSet<>();
    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
        //遍历所有的beanFactoryPostProcessors,
        //将BeanDefinitionRegistryPostProcessor和普通BeanFactoryPostProcessor区分开
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor =
                        (BeanDefinitionRegistryPostProcessor) postProcessor;
               //主要看这里!!!
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            }
            else {
                regularPostProcessors.add(postProcessor);
            }
        }
        ....省略此处代码在之前的文章已经介绍过了

该方法主要做了以下事情:

  • 执行了BeanDefinitionRegistryPostProcessor(此处只有ConfigurationClassPostProcessor)
  • 执行了BeanFactoryPostProcessor
  • 完成了@Configuration配置文件的解析,并且把扫描到的、配置的Bean定义信息都加载进容器里
  • Full模式下,完成了对@Configuration配置文件的加强,使得管理Bean依赖关系更加的方便了

registryProcessor.postProcessBeanDefinitionRegistry(registry)这一步(调用了ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry方法)使用工具ConfigurationClassParser尝试发现所有的配置(@Configuration)类,使用工具ConfigurationClassBeanDefinitionReader注册所发现的配置类中所有的bean定义。结束执行的条件是所有配置类都被发现和处理,相应的bean定义注册到容器。

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
        PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {

2.2 主要看这里

下面看ConfigurationClassPostProcessor类中postProcessBeanDefinitionRegistry()的处理逻辑,该方法使用工具ConfigurationClassParser尝试发现所有的配置(@Configuration)类,使用工具ConfigurationClassBeanDefinitionReader注册所发现的配置类中所有的bean定义。结束执行的条件是所有配置类都被发现和处理,相应的bean定义注册到容器。

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    //根据BeanDefinitionRegistry,生成registryId 是全局唯一的。
    int registryId = System.identityHashCode(registry);
    // 判断,如果这个registryId 已经被执行过了,就不能够再执行了,否则抛出异常
    if (this.registriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
                "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
    }
    if (this.factoriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
                "postProcessBeanFactory already called on this post-processor against " + registry);
    }
    // 已经执行过的registry防止重复执行
    this.registriesPostProcessed.add(registryId);
    // 调用processConfigBeanDefinitions 进行Bean定义的加载
    processConfigBeanDefinitions(registry);
}

2.2.1 处理配置类并注册BeanDefinition

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    // 记录候选配置类
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    // 获取已经注册的bean名称(将容器中已经登记的Bean定义作为候选配置类名称)
    String[] candidateNames = registry.getBeanDefinitionNames();
    // 程序此时处于容器启动的早期,通常此时 candidateNames 中实际上只会有一个配置类(即...Application启动类)
    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        //如果beanDef现在就已经确定了是full或者lite,说明已经被解析过了,所以再来就直接输出debug
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
            }
        }
        // 检查是否是@Configuration的Class,如果是就标记下属性:full 或者lite。
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            //如果当前的bean是Javabean配置类(含有@Configuration注解的类),则加入到集合configCandidates中
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }
    // 如果一个配置文件类都没找到,直接返回
    if (configCandidates.isEmpty()) {
        return;
    }
    // 把这些配置按照@Order注解进行排序(@Configuration注解的配置文件是支持order排序的。但是普通bean不行)
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });
   // 尝试检测自定义的 BeanNameGenerator
    SingletonBeanRegistry sbr = null;
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        if (!this.localBeanNameGeneratorSet) {
            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
            if (generator != null) {
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator;
            }
        }
    }
    // web环境这里都设置了StandardServletEnvironment
    //正常情况下env环境不可能为null(此处做容错处理)
    if (this.environment == null) {
        this.environment = new StandardEnvironment();
    }
    // ConfigurationClassParser是真正解析@Configuration注解的类
    ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    // 表示将要被处理的候选配置类
    // 因为不清楚候选是否确实是配置类,所以使用BeanDefinitionHolder类型记录
    // 这里初始化为方法开始时容器中注解了@Configuration的Bean定义的集合
    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    // 装载已经处理过的配置类,最大长度为:configCandidates.size()
    // 表示已经处理的配置类,已经被处理的配置类已经明确了其类型,所以用 ConfigurationClass 类型记录,
    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    do {
       // 解析目标配置类【第一个解析的是应用程序主类】
        parser.parse(candidates);
        // 主要校验配置类不能使用final修饰符(CGLIB代理是生成一个子类,因此原先的类不能使用final修饰)
        parser.validate();
        // 从分析器parser中获取分析得到的配置类configurationClasses
        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        configClasses.removeAll(alreadyParsed);
        // 如果Reader为null,那就实例化ConfigurationClassBeanDefinitionReader来加载Bean,
       // 并加入到alreadyParsed中,用于去重(避免@ComponentScan直接互扫)
        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                    registry, this.sourceExtractor, this.resourceLoader, this.environment,
                    this.importBeanNameGenerator, parser.getImportRegistry());
        }
        // 此处调用ConfigurationClassBeanDefinitionReader的loadBeanDefinitionsd方法
        // 加载配置文件里面的@Bean/@Import,此方法决定了向容器注册Bean定义信息的顺序
        this.reader.loadBeanDefinitions(configClasses);
        // 刚刚处理完的配置类记录到已处理配置类alreadyParsed集合中
        alreadyParsed.addAll(configClasses);
        // 清空候选配置类集合,为下一轮do循环做初始化准备
        candidates.clear();
        // 如果registry中注册的bean的数量 大于 之前获得的数量
        if (registry.getBeanDefinitionCount() > candidateNames.length) {
            // 则意味着在解析过程中发现并注册了更多的Bean定义到容器中去,这些新注册的Bean定义
            // 也有可能是候选配置类,它们也要被处理用来发现和注册Bean定义
           String[] newCandidateNames = registry.getBeanDefinitionNames();
            Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
            Set<String> alreadyParsedClasses = new HashSet<>();
            for (ConfigurationClass configurationClass : alreadyParsed) {
                alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
            }
            for (String candidateName : newCandidateNames) {
               // 如果老的oldCandidateNames不包含就说明是新进来的候选的Bean定义(即当前 BeanDefinition 是新解析的)
                if (!oldCandidateNames.contains(candidateName)) {
                    BeanDefinition bd = registry.getBeanDefinition(candidateName);
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                            !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                          // 基于 BeanDefinition 创建 BeanDefinitionHolder 并将其写入 candidates
                        candidates.add(new BeanDefinitionHolder(bd, candidateName));
                    }
                }
            }
            candidateNames = newCandidateNames;
        }
    }
    while (!candidates.isEmpty());// 直到所有的配置类都解析完毕
    // 注册 ImportRegistry bean 到 SingletonBeanRegistry 中
    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }
    //清除缓存(元数据缓存)
    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
    }
}

下面文章主要围绕processConfigBeanDefinitions方法做的扩展延伸。

3 解析processConfigBeanDefinitions方法

3.1 概要分析

处理配置类并注册BeanDefinition的方法比较复杂,下面针对方法中一些重要的功能点进行解析:

3.2. 介绍ConfigurationClassUtils工具类
3.3. 解析Java配置类ConfigurationClassParser#parse(Set<BeanDefinitionHolder> configCandidates)

3.3.1 processConfigurationClass解析单个配置类

3.3.1.1 doProcessConfigurationClass

3.3.1.1.1 processMemberClasses

3.3.1.1.2 处理给定的@PropertySource 注解元数据

3.3.1.1.3 @ComponentScan注解解析过程

3.3.1.1.4 processImports

3.3.1.1.5 processInterfaces

3.3.1.2 ConditionEvaluator条件评估

3.3.1.3 ConfigurationClass配置类

3.3.1.4 ConditionalOnProperty

3.4. loadBeanDefinitions加载bean定义信息

3.2 ConfigurationClassUtils工具类

ConfigurationClassUtils工具类用于检查是否是含有@Configuration注解的类,需要注意下面两个核心方法,是如何判断某个类是否为配置类的(判断是full模式,还是lite模式的配置文件):

  • 如果类上有@Configuration注解说明是一个完全(Full)的配置类
  • 如果类上面有@Component,@ComponentScan,@Import,@ImportResource这些注解,那么就是一个简化配置类。如果不是上面两种情况,那么有@Bean注解修饰的方法也是简化配置类
abstract class ConfigurationClassUtils {
    private static final String CONFIGURATION_CLASS_FULL = "full";
    private static final String CONFIGURATION_CLASS_LITE = "lite";
    private static final String CONFIGURATION_CLASS_ATTRIBUTE =
            Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
    private static final String ORDER_ATTRIBUTE =
            Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "order");
    private static final Log logger = LogFactory.getLog(ConfigurationClassUtils.class);
    private static final Set<String> candidateIndicators = new HashSet<>(4);
    static {
        candidateIndicators.add(Component.class.getName());
        candidateIndicators.add(ComponentScan.class.getName());
        candidateIndicators.add(Import.class.getName());
        candidateIndicators.add(ImportResource.class.getName());
    }
    // 只要这个类标注了:@Configuration注解就行(接口、抽象类都没问题)
    public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
        return metadata.isAnnotated(Configuration.class.getName());
    }
    // 判断是Lite模式的条件:(首先肯定没有@Configuration注解)
    // 1、不能是接口
    // 2、但凡只要标注了一个下面注解,都算lite模式:@Component @ComponentScan @Import @ImportResource
    // 3、只要存在有一个方法标注了@Bean注解,那就是lite模式
    public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
        // 不能是接口
        if (metadata.isInterface()) {
            return false;
        }
        // 但凡只有标注了一个下面注解,都算lite模式:@Component @ComponentScan @Import @ImportResource
        for (String indicator : candidateIndicators) {
            if (metadata.isAnnotated(indicator)) {
                return true;
            }
        }
        // 只有存在有一个方法标注了@Bean注解,那就是lite模式
        try {
            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;
        }
    }
    // 不管是Full模式还是Lite模式,都被认为是候选的配置类,是上面两个方法的结合
    public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
        return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
    }
    // 下面两个方法是直接判断Bean定义信息,是否是配置类,至于Bean定义里这个属性什么时候放进去的,请参考
    //ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)方法,
    //它会对每个Bean定义信息进行检测(毕竟刚开始Bean定义信息是非常少的,所以速度也很快)
    public static boolean isFullConfigurationClass(BeanDefinition beanDef) {
        return CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
    }
    public static boolean isLiteConfigurationClass(BeanDefinition beanDef) {
        return CONFIGURATION_CLASS_LITE.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
    }

Full模式和Lite模式的区别:

  • 当@Bean方法声明在没有被@Conguration注解的类里,这就是所谓的以’精简’模式(Lite)处理。例如,在一个@Component中,甚至在一个普通的类中声明的bean方法都会以’精简’处理。
  • 跟完整@Configuration不同的是,精简@Bean方法难以声明bean之间的依赖。通常,在精简模式中操作时,不应该在一个@Bean方法中调用另一个@Bean方法。一种推荐的方式是只在@Configuration类中使用@Bean方法,这样可以确保总是使用’完整’模式,避免@Bean方法意外地被调用多次,减少那些在精简模式下产生的很难跟踪的微妙bugs。

例如:

@Configuration
public class AppConfig {
    @Bean
    public Foo foo() {
        return new Foo(bar()); // 这里调用的bar()方法
    }
    @Bean
    public Bar bar() {
        return new Bar();
    }
}

Foo 接受一个bar的引用来进行构造器注入:这种方法声明的bean的依赖关系只有在@Configuration类的@Bean方法中有效。如果换成@Component(Lite模式),则foo()方法中new Foo(bar())传入的bar()方法会每次产生一个新的Bar对象
结论:
在@Component或其他组建中使用@Bean好处是不会启动CGLIB这种重量级工具(不过在Spring中即使这里不使用,其他很多地方也在使用)。并且@Component及其相关的Stereotype组件自身就有摸框级别的功能,在这里使用@Bean注解能很好的表明一个Bean的从属和结构关系,但是需要注意直接调用方法的“副作用”。
个人建议如果没什么特别的要求就使用@Configuration,引入CGLIB并不会影响多少性能,然而坑会少很多。在spring官网将用@Configuration创建的@Bean称呼为”Full”模式、将@Component创建的@Bean称呼为”‘lite”模式,从字面上也能略知他们的差异。
只有类上标注@Configuration才是full模式。标注有@Component、@ComponentScan、@Import、@ImportResource或者啥注解都没标注但是有被标注了@Bean的方法这种也是lite模式

3.3 解析Java配置类

解过程中

  1. 如果遇到注解了@Component类,直接作为Bean定义注册到容器
  2. 如果注解或者注解的注解中有@Import, 处理所有这些@import,识别配置类,添加到分析器的属性configurationClasses中去

ConfigurationClassParser#parse

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    this.deferredImportSelectors = new LinkedList<>();
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
       // 下面三种方式解析Bean
        try {
        // 我们使用的注解驱动,所以会到这个parse进来处理。
            if (bd instanceof AnnotatedBeanDefinition) {
                // 其实内部调用都是processConfigurationClass进行解析的
                parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
            }
            //只要有注解标注的,都会走这里来解析
            else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
            }
            else {
                parse(bd.getBeanClassName(), holder.getBeanName());
            }
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                    "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
        }
    }
    //处理ImportSelect,执行找到的 DeferredImportSelector
    //DeferredImportSelector 是 ImportSelector 的一个变种。
    // ImportSelector 被设计成其实和@Import注解的类同样的导入效果,但是实现 ImportSelector
    // 的类可以条件性地决定导入哪些配置。
    // DeferredImportSelector 的设计目的是在所有其他的配置类被处理后才处理。这也正是
    // 该语句被放到本函数最后一行的原因。
    processDeferredImportSelectors();
}

该方法做了三件事如下:

  1. 实例化deferredImportSelectors
  2. 遍历configCandidates ,进行处理.根据BeanDefinition 的类型 做不同的处理,一般都会调用ConfigurationClassParser#parse 进行解析
  3. 处理ImportSelect

3.3.1 处理@Configuration配置类

解析@Configuration配置文件,然后加载进Bean的定义信息。可以看到它加载Bean定义信息的一个顺序

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    //ConfigurationCondition继承自Condition接口
    // ConfigurationPhase枚举类型的作用:根据条件来判断是否加载这个配置类
    // 两个值:PARSE_CONFIGURATION 若条件不匹配就不加载此@Configuration
    // REGISTER_BEAN:无论如何,所有@Configurations都将被解析。
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }
    //判断同一个配置类是否重复加载过,如果重复加载过
    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    if (existingClass != null) {
        if (configClass.isImported()) {
            //如果这个配置类已经存在了,后面又被@Import进来了就会走这里,然后做属性合并
            if (existingClass.isImported()) {
                existingClass.mergeImportedBy(configClass);
            }
            return;
        }
        else {
            //从集合中移除旧的配置类,后续逻辑将处理新的配置
            this.configurationClasses.remove(configClass);
            this.knownSuperclasses.values().removeIf(configClass::equals);
        }
    }
    SourceClass sourceClass = asSourceClass(configClass);
    do {
        //【doProcessConfigurationClass】这个方法是解析配置文件的核心方法
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while (sourceClass != null);
    //保存我们所有的配置类(注意:它是一个LinkedHashMap,所以是有序的和bean定义信息息息相关)
    this.configurationClasses.put(configClass, configClass);
}

3.3.1.1 doProcessConfigurationClass

doProcessConfigurationClass方法主要实现从配置类中解析所有bean,包括处理内部类,父类以及各种注解

@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
        throws IOException {
    //配置类上存在 Component注解,则尝试递归处理其内部成员类
    if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
        processMemberClasses(configClass, sourceClass);
    }
    //处理所有 @PropertySource 注解:将目标资源导入到 environment.propertySources 中
    //将所有的 @PropertySource 注解合并到 @PropertySources 注解中,并逐个进行处理
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), PropertySources.class,
            org.springframework.context.annotation.PropertySource.class)) {
        if (this.environment instanceof ConfigurableEnvironment) {
            processPropertySource(propertySource);
        }
        else {
            logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                    "]. Reason: Environment must implement ConfigurableEnvironment");
        }
    }
    //处理所有的 ComponentScan 注解
    //以深度优先的方式递归处理所有扫描到的配置类
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    if (!componentScans.isEmpty() &&
            !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
         //循环处理每个 ComponentScan 注解
        for (AnnotationAttributes componentScan : componentScans) {
            //如果此配置类存在ComponentScan注解,则通过 ComponentScanAnnotationParser立即处理它
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            // 遍历扫描到的所有组件
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
            //若果扫描出的bean定义是配置类(含有@COnfiguration)
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(
                        holder.getBeanDefinition(), this.metadataReaderFactory)) {
                    //继续调用parse,内部再次调用doProcessConfigurationClas()递归解析
                    parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }
    //处理所有的 @Import 注解
    //1.优先处理所有注解上的 @Import 注解导入的配置类
    //2.后处理此类上通过@Import 注解直接导入的配置类
    processImports(configClass, sourceClass, getImports(sourceClass), true);
    //处理@ImportResource注解
    AnnotationAttributes importResource =
            AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
    if (importResource != null) {
        // 读取资源位置
        String[] resources = importResource.getStringArray("locations");
        // 读取 BeanDefinitionReader
        Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
        for (String resource : resources) {
             // 解析占位符
            String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
             // 写入缓存
            configClass.addImportedResource(resolvedResource, readerClass);
        }
    }
    //处理所有的 @Bean 方法,将它们解析为 BeanMethod 并写入配置类中
    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    for (MethodMetadata methodMetadata : beanMethods) {
        //将解析出的所有@Bean注解方法添加到configClass配置类信息中
        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }
    //处理所有接口上非 Abstract 的 @Bean 方法,并添加到configClass配置类信息中
    processInterfaces(configClass, sourceClass);
    // 如果有父类,则返回父类,递归执行doProcessConfigurationClass()解析父类
    if (sourceClass.getMetadata().hasSuperClass()) {
        String superclass = sourceClass.getMetadata().getSuperClassName();
        if (superclass != null && !superclass.startsWith("java") &&
                !this.knownSuperclasses.containsKey(superclass)) {
            // 已处理的父类缓存
            this.knownSuperclasses.put(superclass, configClass);
            return sourceClass.getSuperClass();
        }
    }
     // 此配置类处理完成
    return null;
}
3.3.1.1.1 processMemberClasses
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    // 读取所有的成员类
    Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
     // 存在成员类
    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.add(memberClass);
            }
        }
        // 根据 Order 进行排序
        OrderComparator.sort(candidates);
        for (SourceClass candidate : candidates) {
            // 出现配置类循环导入
            if (this.importStack.contains(configClass)) {
                this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
            }
            else {
               //将此配置类入栈
                this.importStack.push(configClass);
                try {
                   // 处理此配置类
                    processConfigurationClass(candidate.asConfigClass(configClass));
                }
                finally {
                   //解析完成后将其出栈
                    this.importStack.pop();
                }
            }
        }
    }
}
3.3.1.1.2 处理给定的@PropertySource 注解元数据
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
    // 读取名称
    String name = propertySource.getString("name");
    if (!StringUtils.hasLength(name)) {
        name = null;
    }
    // 读取编码
    String encoding = propertySource.getString("encoding");
    if (!StringUtils.hasLength(encoding)) {
        encoding = null;
    }
    // 读取资源位置
    String[] locations = propertySource.getStringArray("value");
    Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
    // 读取资源未找到则忽略标识
    boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
   // 读取 PropertySourceFactory
    Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
    PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
            DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
    // 循环处理每个资源
    for (String location : locations) {
        try {
           // 解析占位符
            String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
             // 读取资源
           Resource resource = this.resourceLoader.getResource(resolvedLocation);
             // 创建 ResourcePropertySource 并加入到 environment 中
           addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
        }
        catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) {
             // 占位符解析失败或资源未找到
            if (ignoreResourceNotFound) {
                if (logger.isInfoEnabled()) {
                    logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
                }
            }
            else {
                throw ex;
            }
        }
    }
}
3.3.1.1.3 @ComponentScan注解解析过程

@ComponentScan注解解析通过调用ComponentScanAnnotationParser的parse方法完成,而parse()方法内部处理了一些scanner属性(过滤器设置)和basePackages包名处理,最终通过调用ClassPathBeanDefinitionScanner.doScan方法实现扫面工作。

3.3.1.1.3.1 ComponentScan 注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    /**
     *  基础包名称
     */
    @AliasFor("basePackages")
    String[] value() default {};
    /**
     *  基础包名称
     */
    @AliasFor("value")
    String[] basePackages() default {};
    /**
     *  基础包类【读取指定类所在的包路径】
     */
    Class<?>[] basePackageClasses() default {};
    /**
     *  用于生成 bean 名称的 BeanNameGenerator
     */
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
    /**
     *  范围解析器
     */
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
    /**
     *  是否需要为目标组件生成代理,默认不生成
     */
    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
    /**
     *  资源模式
     */
    String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
    /**
     *  是否使用默认的过滤器
     *  自动检测 @Component、@Repository、@Service、@Controller 注解标注的类
     */
    boolean useDefaultFilters() default true;
    /**
     *  指定扫描哪些类型
     */
    Filter[] includeFilters() default {};
    /**
     *  指定排除哪些类型
     */
    Filter[] excludeFilters() default {};
    /**
     *  扫描到的单例 bean 是否需要延迟初始化
     */
    boolean lazyInit() default false;
    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    @interface Filter {
        /**
         *  过滤类型,默认是基于注解
         */
        FilterType type() default FilterType.ANNOTATION;
        /**
         *  用作筛选器的类,多个类之间是逻辑或的关系
         */
        @AliasFor("classes")
        Class<?>[] value() default {};
        /**
         *  用作筛选器的类,多个类之间是逻辑或的关系
         */
        @AliasFor("value")
        Class<?>[] classes() default {};
        /**
         *  匹配模式,根据 FilterType 分流
         */
        String[] pattern() default {};
    }
}
3.3.1.1.3.2 ComponentScan 注解解析器
/**
 *  @ComponentScan 注解解析器
 */
class ComponentScanAnnotationParser {
    private final Environment environment;
    private final ResourceLoader resourceLoader;
    private final BeanNameGenerator beanNameGenerator;
    private final BeanDefinitionRegistry registry;
    public ComponentScanAnnotationParser(Environment environment, ResourceLoader resourceLoader,
            BeanNameGenerator beanNameGenerator, BeanDefinitionRegistry registry) {
        this.environment = environment;
        this.resourceLoader = resourceLoader;
        this.beanNameGenerator = beanNameGenerator;
        this.registry = registry;
    }
    /**
     *  解析指定的 @ComponentScan 注解
     */
    public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
        // 类路径 BeanDefinition 扫描器
        final ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry,
                componentScan.getBoolean("useDefaultFilters"), environment, resourceLoader);
        // 设置扫描器的 BeanNameGenerator
        final Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
        final boolean useInheritedGenerator = BeanNameGenerator.class == generatorClass;
        scanner.setBeanNameGenerator(useInheritedGenerator ? beanNameGenerator :
            BeanUtils.instantiateClass(generatorClass));
        // 尝试设置扫描器的 ScopedProxyMode
        final ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
        if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
            scanner.setScopedProxyMode(scopedProxyMode);
        }
        else {
            final Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
            scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
        }
        // 设置扫描器的资源模式
        scanner.setResourcePattern(componentScan.getString("resourcePattern"));
        // 添加包含过滤器,默认无
        for (final AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
            for (final TypeFilter typeFilter : typeFiltersFor(filter)) {
                scanner.addIncludeFilter(typeFilter);
            }
        }
        // 添加排序过滤器
        for (final AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
            for (final TypeFilter typeFilter : typeFiltersFor(filter)) {
                scanner.addExcludeFilter(typeFilter);
            }
        }
        // 设置延迟初始化属性
        final boolean lazyInit = componentScan.getBoolean("lazyInit");
        if (lazyInit) {
            scanner.getBeanDefinitionDefaults().setLazyInit(true);
        }
        final Set<String> basePackages = new LinkedHashSet<>();
        // 尝试读取 basePackages 属性
        final String[] basePackagesArray = componentScan.getStringArray("basePackages");
        for (final String pkg : basePackagesArray) {
            // 解析占位符,并按照 ,;\t\n 切割包路径
            final String[] tokenized = StringUtils.tokenizeToStringArray(environment.resolvePlaceholders(pkg),
                    ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
            Collections.addAll(basePackages, tokenized);
        }
        // 读取 basePackageClasses,并提取出包路径
        for (final Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
            basePackages.add(ClassUtils.getPackageName(clazz));
        }
        /**
         *  如果 basePackages 和 basePackageClasses 都未配置,
         *  则以 @ComponentScan 注解所在配置类的包路径作为基础包
         */
        if (basePackages.isEmpty()) {
            basePackages.add(ClassUtils.getPackageName(declaringClass));
        }
        // 忽略此配置类
        scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
            @Override
            protected boolean matchClassName(String className) {
                return declaringClass.equals(className);
            }
        });
        // 执行包扫描
        return scanner.doScan(StringUtils.toStringArray(basePackages));
    }
    private List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
        final List<TypeFilter> typeFilters = new ArrayList<>();
        // 读取过滤类型
        final FilterType filterType = filterAttributes.getEnum("type");
        // 读取所有的 classes
        for (final Class<?> filterClass : filterAttributes.getClassArray("classes")) {
            switch (filterType) {
                // 1)过滤类型为基于注解
                case ANNOTATION:
                    // 目标 class 是否是注解
                    Assert.isAssignable(Annotation.class, filterClass,
                            "@ComponentScan ANNOTATION type filter requires an annotation type");
                    @SuppressWarnings("unchecked") final
                    Class<Annotation> annotationType = (Class<Annotation>) filterClass;
                    // 添加注解类型过滤器
                    typeFilters.add(new AnnotationTypeFilter(annotationType));
                    break;
                    // 2)过滤类型为基于目标类型及其子类
                case ASSIGNABLE_TYPE:
                    // 添加类型过滤器
                    typeFilters.add(new AssignableTypeFilter(filterClass));
                    break;
                    // 3)过滤类型为基于自定义过滤器
                case CUSTOM:
                    // 添加自定义 TypeFilter
                    Assert.isAssignable(TypeFilter.class, filterClass,
                            "@ComponentScan CUSTOM type filter requires a TypeFilter implementation");
                    final TypeFilter filter = BeanUtils.instantiateClass(filterClass, TypeFilter.class);
                    ParserStrategyUtils.invokeAwareMethods(
                            filter, environment, resourceLoader, registry);
                    typeFilters.add(filter);
                    break;
                default:
                    throw new IllegalArgumentException("Filter type not supported with Class value: " + filterType);
            }
        }
        // 如果指定了匹配模式
        for (final String expression : filterAttributes.getStringArray("pattern")) {
            switch (filterType) {
                // 过滤类型为 ASPECTJ
                case ASPECTJ:
                    typeFilters.add(new AspectJTypeFilter(expression, resourceLoader.getClassLoader()));
                    break;
                    // 过滤类型为 REGEX
                case REGEX:
                    typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(expression)));
                    break;
                default:
                    throw new IllegalArgumentException("Filter type not supported with String pattern: " + filterType);
            }
        }
        return typeFilters;
    }
}
3.3.1.1.3.3 doScan
//ClassPathBeanDefinitionScanner#执行包扫描
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    final Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (final String basePackage : basePackages) {
        //根据basePackage加载包下所有java文件,并扫描出所有bean组件,
        //findCandidateComponents方法内部调用
        //ClassPathScanningCandidateComponentProvider.scanCandidateComponents(backPackages)
        final Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        //遍历beandefition
        for (final BeanDefinition candidate : candidates) {
            //解析作用域Scope
            final ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            final String beanName = beanNameGenerator.generateBeanName(candidate, registry);
            if (candidate instanceof AbstractBeanDefinition) {
                // 应用默认配置
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            //通用注解解析到candidate结构中,主要是处理Lazy, primary DependsOn, Role ,Description这五个注解
            if (candidate instanceof AnnotatedBeanDefinition) {
                // 处理 BeanDefinition 相关注解
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            //检查当前bean是否已经注册,不存在则注册
            if (checkCandidate(beanName, candidate)) {
                // 创建 BeanDefinitionHolder
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                // 尝试应用代理模式
                definitionHolder =
                        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, registry);
                // 添加到 beanDefinitions 进行循环处理
                beanDefinitions.add(definitionHolder);
                // 注册到ioc容器中,主要是一些@Component组件,@Bean注解方法并没有在此处注册,
                // definitionHolder: beanname和beandefinition 键值对
                registerBeanDefinition(definitionHolder, registry);
            }
        }
    }
    return beanDefinitions;
}
3.3.1.1.3.4 AnnotationConfigUtils
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
    processCommonDefinitionAnnotations(abd, abd.getMetadata());
}
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
    // 1)目标元素存在 @Lazy 注解
    AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
    if (lazy != null) {
        abd.setLazyInit(lazy.getBoolean("value"));
    }
    else if (abd.getMetadata() != metadata) {
        lazy = attributesFor(abd.getMetadata(), Lazy.class);
        if (lazy != null) {
            abd.setLazyInit(lazy.getBoolean("value"));
        }
    }
    // 2)目标元素存在 @Primary 注解
    if (metadata.isAnnotated(Primary.class.getName())) {
        abd.setPrimary(true);
    }
    // 3)目标元素存在 @DependsOn 注解
    final AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
    if (dependsOn != null) {
        abd.setDependsOn(dependsOn.getStringArray("value"));
    }
    // 4)目标元素存在 @Role 注解
    final AnnotationAttributes role = attributesFor(metadata, Role.class);
    if (role != null) {
        abd.setRole(role.getNumber("value").intValue());
    }
    // 5)目标元素存在 @Description 注解
    final AnnotationAttributes description = attributesFor(metadata, Description.class);
    if (description != null) {
        abd.setDescription(description.getString("value"));
    }
}
static BeanDefinitionHolder applyScopedProxyMode(
        ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
    // 读取代理模式
    final ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
    if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
        return definition;
    }
    // 如果是基于 CGLIB 的类代理
    final boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
    return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
3.3.1.1.3.5 ClassPathScanningCandidateComponentProvider
//扫描指定的类路径
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    if (componentsIndex != null && indexSupportsIncludeFilters()) {
        return addCandidateComponentsFromIndex(componentsIndex, basePackage);
    }
    else {
        // 扫描组件
        return scanCandidateComponents(basePackage);
    }
}
//实现bean定义信息扫描
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    final Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
        // @ComponentScan("com.sl.springlearning.extension")包路径处理:
        // packageSearchPath = classpath*:com/sl/springlearning/extension/**/*.class
        final String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                resolveBasePackage(basePackage) + '/' + resourcePattern;
        // 通过 ServletContextResourcePatternResolver 读取所有资源(当前包下所有的class文件)
        final Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
        final boolean traceEnabled = logger.isTraceEnabled();
        final boolean debugEnabled = logger.isDebugEnabled();
        // 循环处理所有资源
        for (final Resource resource : resources) {
            if (traceEnabled) {
                logger.trace("Scanning " + resource);
            }
            // 资源是可读取的
            if (resource.isReadable()) {
                try {
                    // 读取 MetadataReader
                    final MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    //按照scanner过滤器过滤,比如配置类本身将被过滤掉,没有@Component等组件注解的类将过滤掉
                    if (isCandidateComponent(metadataReader)) {
                        // 基于 MetadataReader 创建 ScannedGenericBeanDefinition
                        final ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setResource(resource);
                        sbd.setSource(resource);
                        // 是否是候选组件
                        if (isCandidateComponent(sbd)) {
                            if (debugEnabled) {
                                logger.debug("Identified candidate component class: " + resource);
                            }
                            candidates.add(sbd);
                        }
                        else {
                            if (debugEnabled) {
                                logger.debug("Ignored because not a concrete top-level class: " + resource);
                            }
                        }
                    }
                    else {
                        if (traceEnabled) {
                            logger.trace("Ignored because not matching any filter: " + resource);
                        }
                    }
                }
                catch (final Throwable ex) {
                    throw new BeanDefinitionStoreException(
                            "Failed to read candidate component class: " + resource, ex);
                }
            }
            else {
                if (traceEnabled) {
                    logger.trace("Ignored because not readable: " + resource);
                }
            }
        }
    }
    catch (final IOException ex) {
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    }
    return candidates;
}
/**
 *  将类名解析为资源路径
 *  为了避免多余的替换操作,可以直接使用 / 作为包分隔符
 */
protected String resolveBasePackage(String basePackage) {
    return ClassUtils.convertClassNameToResourcePath(getEnvironment().resolveRequiredPlaceholders(basePackage));
}
/**
 *  目标类不匹配任何排除过滤器,并且至少匹配一个包含过滤器
 */
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    for (final TypeFilter tf : excludeFilters) {
        // 匹配当期排除过滤器
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return false;
        }
    }
    for (final TypeFilter tf : includeFilters) {
        // 匹配当前包含过滤器
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return isConditionMatch(metadataReader);
        }
    }
    return false;
}
/**
 *  目标 BeanDefinition 是否是一个候选组件
 */
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    final AnnotationMetadata metadata = beanDefinition.getMetadata();
    /**
     *  目标类型不是接口,并且不依赖于封闭类【不是内部类】
     */
    return metadata.isIndependent() && (metadata.isConcrete() ||
            metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()));
}
3.3.1.1.3.6 ServletContextResourcePatternResolver
/**
 * 可配置 ServletContext 的 PathMatchingResourcePatternResolver
 */
public class ServletContextResourcePatternResolver extends PathMatchingResourcePatternResolver {
    private static final Log logger = LogFactory.getLog(ServletContextResourcePatternResolver.class);
    public ServletContextResourcePatternResolver(ServletContext servletContext) {
        super(new ServletContextResourceLoader(servletContext));
    }
    public ServletContextResourcePatternResolver(ResourceLoader resourceLoader) {
        super(resourceLoader);
    }
    @Override
    protected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern)
            throws IOException {
        // 如果跟路径资源是 ServletContextResource
        if (rootDirResource instanceof ServletContextResource) {
            final ServletContextResource scResource = (ServletContextResource) rootDirResource;
            final ServletContext sc = scResource.getServletContext();
            final String fullPattern = scResource.getPath() + subPattern;
            final Set<Resource> result = new LinkedHashSet<>(8);
            doRetrieveMatchingServletContextResources(sc, fullPattern, scResource.getPath(), result);
            return result;
        }
        else {
            // 默认是 UrlResource
            return super.doFindPathMatchingFileResources(rootDirResource, subPattern);
        }
    }
}
3.3.1.1.3.7 PathMatchingResourcePatternResolver
@Override
public Resource[] getResources(String locationPattern) throws IOException {
    Assert.notNull(locationPattern, "Location pattern must not be null");
    // 资源路径以 classpath*: 开头
    if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
        /**
         * 支持多个同名文件
         * a class path resource (multiple resources for same name possible)
         * 资源路径是 Ant 风格的通配符
         */
        if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
            // a class path resource pattern
            return findPathMatchingResources(locationPattern);
        }
        else {
            // 读取 classpath 特定根路径下的所有资源
            return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
        }
    }
    else {
        // Generally only look for a pattern after a prefix here, and on Tomcat only after the "*/" separator for its "war:" protocol.
        final int prefixEnd = locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
            locationPattern.indexOf(':') + 1;
        if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
            // a file pattern
            return findPathMatchingResources(locationPattern);
        }
        else {
            // a single resource with the given name
            return new Resource[] {getResourceLoader().getResource(locationPattern)};
        }
    }
}
/**
 *  通过 Ant 风格的路径匹配器查找所有匹配资源
 */
protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
    // 确定给定位置的根目录:classpath*:org/zxd/spring5/
    final String rootDirPath = determineRootDir(locationPattern);
    // 截取模糊匹配路径:**/*.class
    final String subPattern = locationPattern.substring(rootDirPath.length());
    // 读取根路径 Resource
    final Resource[] rootDirResources = getResources(rootDirPath);
    final Set<Resource> result = new LinkedHashSet<>(16);
    // 遍历所有根路径
    for (Resource rootDirResource : rootDirResources) {
        rootDirResource = resolveRootDirResource(rootDirResource);
        // 获取根路径 URL
        URL rootDirUrl = rootDirResource.getURL();
        // 1)URL 协议以 bundle 开头
        if (equinoxResolveMethod != null && rootDirUrl.getProtocol().startsWith("bundle")) {
            final URL resolvedUrl = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirUrl);
            if (resolvedUrl != null) {
                rootDirUrl = resolvedUrl;
            }
            rootDirResource = new UrlResource(rootDirUrl);
        }
        // 2)URL 协议以 vfs 开头
        if (rootDirUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
            result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirUrl, subPattern, getPathMatcher()));
        }
        // 3)URL 是一个 jar:jar、war、zip、vfszip、wsjar
        else if (ResourceUtils.isJarURL(rootDirUrl) || isJarResource(rootDirResource)) {
            result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirUrl, subPattern));
        }
        else {
            // 4)URL 协议以 file 开头
            result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
        }
    }
    if (logger.isTraceEnabled()) {
        logger.trace("Resolved location pattern [" + locationPattern + "] to resources " + result);
    }
    return result.toArray(new Resource[0]);
}
protected Resource[] findAllClassPathResources(String location) throws IOException {
    String path = location;
    if (path.startsWith("/")) {
        path = path.substring(1);
    }
    // 读取所有的 ClassPathResource
    final Set<Resource> result = doFindAllClassPathResources(path);
    if (logger.isTraceEnabled()) {
        logger.trace("Resolved classpath location [" + location + "] to resources " + result);
    }
    return result.toArray(new Resource[0]);
}
protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
    final Set<Resource> result = new LinkedHashSet<>(16);
    // 读取类加载器
    final ClassLoader cl = getClassLoader();
    // 读取指定包路径【org/zxd/spring5/】下所有资源的 URL
    final Enumeration<URL> resourceUrls = cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path);
    while (resourceUrls.hasMoreElements()) {
        final URL url = resourceUrls.nextElement();
        result.add(convertClassLoaderURL(url));
    }
    if ("".equals(path)) {
        // The above result is likely to be incomplete, i.e. only containing file system references.
        // We need to have pointers to each of the jar files on the classpath as well...
        addAllClassLoaderJarRoots(cl, result);
    }
    return result;
}
/**
 *  将 URL 转换为  UrlResource
 */
protected Resource convertClassLoaderURL(URL url) {
    return new UrlResource(url);
}
3.3.1.1.3.8 ConfigurationClassBeanDefinitionReader

配置类 BeanDefinition 读取器

@Override
public Resource[] getResources(String locationPattern) throws IOException {
    Assert.notNull(locationPattern, "Location pattern must not be null");
    // 资源路径以 classpath*: 开头
    if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
        /**
         * 支持多个同名文件
         * a class path resource (multiple resources for same name possible)
         * 资源路径是 Ant 风格的通配符
         */
        if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
            // a class path resource pattern
            return findPathMatchingResources(locationPattern);
        }
        else {
            // 读取 classpath 特定根路径下的所有资源
            return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
        }
    }
    else {
        // Generally only look for a pattern after a prefix here, and on Tomcat only after the "*/" separator for its "war:" protocol.
        final int prefixEnd = locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
            locationPattern.indexOf(':') + 1;
        if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
            // a file pattern
            return findPathMatchingResources(locationPattern);
        }
        else {
            // a single resource with the given name
            return new Resource[] {getResourceLoader().getResource(locationPattern)};
        }
    }
}
/**
 *  通过 Ant 风格的路径匹配器查找所有匹配资源
 */
protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
    // 确定给定位置的根目录:classpath*:org/zxd/spring5/
    final String rootDirPath = determineRootDir(locationPattern);
    // 截取模糊匹配路径:**/*.class
    final String subPattern = locationPattern.substring(rootDirPath.length());
    // 读取根路径 Resource
    final Resource[] rootDirResources = getResources(rootDirPath);
    final Set<Resource> result = new LinkedHashSet<>(16);
    // 遍历所有根路径
    for (Resource rootDirResource : rootDirResources) {
        rootDirResource = resolveRootDirResource(rootDirResource);
        // 获取根路径 URL
        URL rootDirUrl = rootDirResource.getURL();
        // 1)URL 协议以 bundle 开头
        if (equinoxResolveMethod != null && rootDirUrl.getProtocol().startsWith("bundle")) {
            final URL resolvedUrl = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirUrl);
            if (resolvedUrl != null) {
                rootDirUrl = resolvedUrl;
            }
            rootDirResource = new UrlResource(rootDirUrl);
        }
        // 2)URL 协议以 vfs 开头
        if (rootDirUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
            result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirUrl, subPattern, getPathMatcher()));
        }
        // 3)URL 是一个 jar:jar、war、zip、vfszip、wsjar
        else if (ResourceUtils.isJarURL(rootDirUrl) || isJarResource(rootDirResource)) {
            result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirUrl, subPattern));
        }
        else {
            // 4)URL 协议以 file 开头
            result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
        }
    }
    if (logger.isTraceEnabled()) {
        logger.trace("Resolved location pattern [" + locationPattern + "] to resources " + result);
    }
    return result.toArray(new Resource[0]);
}
protected Resource[] findAllClassPathResources(String location) throws IOException {
    String path = location;
    if (path.startsWith("/")) {
        path = path.substring(1);
    }
    // 读取所有的 ClassPathResource
    final Set<Resource> result = doFindAllClassPathResources(path);
    if (logger.isTraceEnabled()) {
        logger.trace("Resolved classpath location [" + location + "] to resources " + result);
    }
    return result.toArray(new Resource[0]);
}
protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
    final Set<Resource> result = new LinkedHashSet<>(16);
    // 读取类加载器
    final ClassLoader cl = getClassLoader();
    // 读取指定包路径【org/zxd/spring5/】下所有资源的 URL
    final Enumeration<URL> resourceUrls = cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path);
    while (resourceUrls.hasMoreElements()) {
        final URL url = resourceUrls.nextElement();
        result.add(convertClassLoaderURL(url));
    }
    if ("".equals(path)) {
        // The above result is likely to be incomplete, i.e. only containing file system references.
        // We need to have pointers to each of the jar files on the classpath as well...
        addAllClassLoaderJarRoots(cl, result);
    }
    return result;
}
/**
 *  将 URL 转换为  UrlResource
 */
protected Resource convertClassLoaderURL(URL url) {
    return new UrlResource(url);
}
3.3.1.1.4 处理所有的 @Import 注解
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
            Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
    // 如果配置类上没有任何候选@Import(importCandidates),
    //说明没有需要处理的导入,则什么都不用做,直接返回
    if (importCandidates.isEmpty()) {
        return;
    }
    // 进行循环依赖的检查
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        // 如果要求做循环导入检查,并且检查到了循环依赖,报告这个问题
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    }
    else {
     // 开始处理配置类configClass上所有的@Import importCandidates
        this.importStack.push(configClass);
        try {
           // 循环处理每一个@Import,每个@Import可能导入三种类型的类 :
            // 1. ImportSelector
            // 2. ImportBeanDefinitionRegistrar
            // 3. 其他类型,都当作配置类处理,也就是相当于使用了注解@Configuration的配置类
            // 下面的for循环中对这三种情况执行了不同的处理逻辑
            for (SourceClass candidate : importCandidates) {
                  // 目标类是 ImportSelector 实例
                if (candidate.isAssignable(ImportSelector.class)) {
                    Class<?> candidateClass = candidate.loadClass();
                     // 创建目标实例
                    ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
                    // 执行 BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware 注入
                    ParserStrategyUtils.invokeAwareMethods(
                            selector, this.environment, this.resourceLoader, this.registry);
                       // 如果这个类也是DeferredImportSelector接口的实现类,
                // 那么加入ConfigurationClassParser的deferredImportSelectors
                    if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
                        this.deferredImportSelectors.add(
                                new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
                    }
                    else {//如果不是,则调用processImports 进行处理.
                     // 获取所有配置类名称
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                       // 获取所有配置类名称
                      Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                        // 递归处理所有导入的配置类
                      processImports(configClass, currentSourceClass, importSourceClasses, false);
                    }
                }
                 // 如果这个类是ImportBeanDefinitionRegistrar接口的实现类
            // 设置到配置类的importBeanDefinitionRegistrars属性中
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    Class<?> candidateClass = candidate.loadClass();
                   // 实例化 ImportBeanDefinitionRegistrar
                    ImportBeanDefinitionRegistrar registrar =
                            BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
                      // 执行 Aware 注入
                    ParserStrategyUtils.invokeAwareMethods(
                            registrar, this.environment, this.resourceLoader, this.registry);
                      // 写入 importBeanDefinitionRegistrars 缓存
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                }
                else {
                    //配置类不是 ImportSelector or ImportBeanDefinitionRegistrar,
                  //则加入到importStack后调用processConfigurationClass 进行处理.
                    // 其它情况下把这个类入队到ConfigurationClassParser的importStack(队列)属性中
                // 然后把这个类当成是@Configuration注解修饰的类递归重头开始解析这个类
                    this.importStack.registerImport(
                            currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                    processConfigurationClass(candidate.asConfigClass(configClass));
                }
            }
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                    "Failed to process import candidates for configuration class [" +
                    configClass.getMetadata().getClassName() + "]", ex);
        }
        finally {
            this.importStack.pop();
        }
    }
}
3.3.1.1.5 processInterfaces
/**
 *  解析接口上的方法,如果此方法存在 @Bean 注解
 */
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    for (final SourceClass ifc : sourceClass.getInterfaces()) {
        final Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
        for (final MethodMetadata methodMetadata : beanMethods) {
            if (!methodMetadata.isAbstract()) {
                // A default method or other concrete method on a Java 8+ interface...
                configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
            }
        }
        processInterfaces(configClass, ifc);
    }
}

3.3.1.2 ConditionEvaluator条件评估

用于计算 @Conditional 注解的内部类

class ConditionEvaluator {
    private final ConditionContextImpl context;
    public ConditionEvaluator(@Nullable BeanDefinitionRegistry registry,
            @Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
        context = new ConditionContextImpl(registry, environment, resourceLoader);
    }
    /**
     *  指定类或方法上是否存在 @Conditional 注解,并需要跳过处理流程
     */
    public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
        return shouldSkip(metadata, null);
    }
    public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
        // 注解元数据为空 || 目标元素不存在 @Conditional 注解,不跳过
        if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
            return false;
        }
        if (phase == null) {
            if (metadata instanceof AnnotationMetadata &&
                    ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
                return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
            }
            return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
        }
        final List<Condition> conditions = new ArrayList<>();
        // 读取所有的条件类
        for (final String[] conditionClasses : getConditionClasses(metadata)) {
            for (final String conditionClass : conditionClasses) {
                final Condition condition = getCondition(conditionClass, context.getClassLoader());
                conditions.add(condition);
            }
        }
        // 根据 Order 进行排序
        AnnotationAwareOrderComparator.sort(conditions);
        for (final Condition condition : conditions) {
            ConfigurationPhase requiredPhase = null;
            if (condition instanceof ConfigurationCondition) {
                requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
            }
            // 请求阶段为空或请求阶段==此阶段 && 此条件不匹配
            if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(context, metadata)) {
                return true;
            }
        }
        // 所有的条件都匹配
        return false;
    }
    @SuppressWarnings("unchecked")
    private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
        // 读取所有 @Conditional 注解的属性配置
        final MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(Conditional.class.getName(), true);
        // 读取评估条件
        final Object values = attributes != null ? attributes.get("value") : null;
        return (List<String[]>) (values != null ? values : Collections.emptyList());
    }
    /**
     *  实例化目标条件
     */
    private Condition getCondition(String conditionClassName, @Nullable ClassLoader classloader) {
        final Class<?> conditionClass = ClassUtils.resolveClassName(conditionClassName, classloader);
        return (Condition) BeanUtils.instantiateClass(conditionClass);
    }
    private static class ConditionContextImpl implements ConditionContext {
        @Nullable
        private final BeanDefinitionRegistry registry;
        @Nullable
        private final ConfigurableListableBeanFactory beanFactory;
        private final Environment environment;
        private final ResourceLoader resourceLoader;
        @Nullable
        private final ClassLoader classLoader;
        public ConditionContextImpl(@Nullable BeanDefinitionRegistry registry,
                @Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
            this.registry = registry;
            beanFactory = deduceBeanFactory(registry);
            this.environment = environment != null ? environment : deduceEnvironment(registry);
            this.resourceLoader = resourceLoader != null ? resourceLoader : deduceResourceLoader(registry);
            classLoader = deduceClassLoader(resourceLoader, beanFactory);
        }
        @Nullable
        private ConfigurableListableBeanFactory deduceBeanFactory(@Nullable BeanDefinitionRegistry source) {
            if (source instanceof ConfigurableListableBeanFactory) {
                return (ConfigurableListableBeanFactory) source;
            }
            if (source instanceof ConfigurableApplicationContext) {
                return ((ConfigurableApplicationContext) source).getBeanFactory();
            }
            return null;
        }
        /**
         *  推断 Environment
         */
        private Environment deduceEnvironment(@Nullable BeanDefinitionRegistry source) {
            if (source instanceof EnvironmentCapable) {
                return ((EnvironmentCapable) source).getEnvironment();
            }
            return new StandardEnvironment();
        }
        /**
         *  推断 ResourceLoader
         */
        private ResourceLoader deduceResourceLoader(@Nullable BeanDefinitionRegistry source) {
            if (source instanceof ResourceLoader) {
                return (ResourceLoader) source;
            }
            return new DefaultResourceLoader();
        }
        /**
         *  推断 ClassLoader
         */
        @Nullable
        private ClassLoader deduceClassLoader(@Nullable ResourceLoader resourceLoader,
                @Nullable ConfigurableListableBeanFactory beanFactory) {
            if (resourceLoader != null) {
                final ClassLoader classLoader = resourceLoader.getClassLoader();
                if (classLoader != null) {
                    return classLoader;
                }
            }
            if (beanFactory != null) {
                return beanFactory.getBeanClassLoader();
            }
            return ClassUtils.getDefaultClassLoader();
        }
        @Override
        public BeanDefinitionRegistry getRegistry() {
            Assert.state(registry != null, "No BeanDefinitionRegistry available");
            return registry;
        }
        @Override
        @Nullable
        public ConfigurableListableBeanFactory getBeanFactory() {
            return beanFactory;
        }
        @Override
        public Environment getEnvironment() {
            return environment;
        }
        @Override
        public ResourceLoader getResourceLoader() {
            return resourceLoader;
        }
        @Override
        @Nullable
        public ClassLoader getClassLoader() {
            return classLoader;
        }
    }
}

3.3.1.3 ConfigurationClass配置类

ConfigurationClass代表一个配置类,它内部维护了一些已经解析好的但是还没有被加入进Bean定义信息的原始信息,有必要做如下解释:

//它是普通的类,基本只有get set方法
final class ConfigurationClass {
    private final AnnotationMetadata metadata;
    private final Resource resource;
    @Nullable
    private String beanName;
    private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);
    // 存储该配置类里所有标注@Bean注解的方法~~~~
    private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();
    // 用Map保存着@ImportResource 导入进来的资源们~
    private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
            new LinkedHashMap<>();
    // 用Map保存着@Import中实现了`ImportBeanDefinitionRegistrar`接口的内容~
    private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
            new LinkedHashMap<>();
    final Set<String> skippedBeanMethods = new HashSet<>();
}

3.3.1.4 ConditionalOnProperty

/**
 *  此 Environment 中是否存在指定的属性 && 属性具有存在特定值【如果指定】。
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class) // 通过 @Conditional 注解关联条件类
public @interface ConditionalOnProperty {
    /**
     *  属性的名称
     */
    String[] value() default {};
    /**
     *  每个属性的前缀
     */
    String prefix() default "";
    /**
     *  属性的名称
     */
    String[] name() default {};
    /**
     *  属性值
     */
    String havingValue() default "";
    /**
     *  如果 Environment 中不存在此属性,是否匹配【默认不匹配】
     */
    boolean matchIfMissing() default false;
}
/**
 * 组件被注册到 BeanDefinitionRegistry 时必须满足的条件
 */
@FunctionalInterface
public interface Condition {
    /**
     *  判断此条件是否满足
     */
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
public abstract class SpringBootCondition implements Condition {
    private final Log logger = LogFactory.getLog(getClass());
    @Override
    public final boolean matches(ConditionContext context,
            AnnotatedTypeMetadata metadata) {
        // 读取类名或方法名称
        String classOrMethodName = getClassOrMethodName(metadata);
        try {
            // 读取条件的输出结果
            ConditionOutcome outcome = getMatchOutcome(context, metadata);
            // 记录日志
            logOutcome(classOrMethodName, outcome);
            // 记录评估结果
            recordEvaluation(context, classOrMethodName, outcome);
            // 此条件是否满足
            return outcome.isMatch();
        }
        catch (NoClassDefFoundError ex) {
            throw new IllegalStateException(
                    "Could not evaluate condition on " + classOrMethodName + " due to "
                            + ex.getMessage() + " not "
                            + "found. Make sure your own configuration does not rely on "
                            + "that class. This can also happen if you are "
                            + "@ComponentScanning a springframework package (e.g. if you "
                            + "put a @ComponentScan in the default package by mistake)",
                    ex);
        }
        catch (RuntimeException ex) {
            throw new IllegalStateException(
                    "Error processing condition on " + getName(metadata), ex);
        }
    }
    private String getName(AnnotatedTypeMetadata metadata) {
        if (metadata instanceof AnnotationMetadata) {
            return ((AnnotationMetadata) metadata).getClassName();
        }
        if (metadata instanceof MethodMetadata) {
            MethodMetadata methodMetadata = (MethodMetadata) metadata;
            return methodMetadata.getDeclaringClassName() + "."
                    + methodMetadata.getMethodName();
        }
        return metadata.toString();
    }
    private static String getClassOrMethodName(AnnotatedTypeMetadata metadata) {
        if (metadata instanceof ClassMetadata) {
            ClassMetadata classMetadata = (ClassMetadata) metadata;
            return classMetadata.getClassName();
        }
        MethodMetadata methodMetadata = (MethodMetadata) metadata;
        return methodMetadata.getDeclaringClassName() + "#"
                + methodMetadata.getMethodName();
    }
    protected final void logOutcome(String classOrMethodName, ConditionOutcome outcome) {
        if (this.logger.isTraceEnabled()) {
            this.logger.trace(getLogMessage(classOrMethodName, outcome));
        }
    }
    private StringBuilder getLogMessage(String classOrMethodName,
            ConditionOutcome outcome) {
        StringBuilder message = new StringBuilder();
        message.append("Condition ");
        message.append(ClassUtils.getShortName(getClass()));
        message.append(" on ");
        message.append(classOrMethodName);
        message.append(outcome.isMatch() ? " matched" : " did not match");
        if (StringUtils.hasLength(outcome.getMessage())) {
            message.append(" due to ");
            message.append(outcome.getMessage());
        }
        return message;
    }
    private void recordEvaluation(ConditionContext context, String classOrMethodName,
            ConditionOutcome outcome) {
        if (context.getBeanFactory() != null) {
            ConditionEvaluationReport.get(context.getBeanFactory())
                    .recordConditionEvaluation(classOrMethodName, this, outcome);
        }
    }
    /**
     *  确定匹配结果
     */
    public abstract ConditionOutcome getMatchOutcome(ConditionContext context,
            AnnotatedTypeMetadata metadata);
    /**
     *  只要有一个条件满足
     */
    protected final boolean anyMatches(ConditionContext context,
            AnnotatedTypeMetadata metadata, Condition... conditions) {
        for (Condition condition : conditions) {
            if (matches(context, metadata, condition)) {
                return true;
            }
        }
        return false;
    }
    /**
     *  指定的条件是否满足
     */
    protected final boolean matches(ConditionContext context,
            AnnotatedTypeMetadata metadata, Condition condition) {
        if (condition instanceof SpringBootCondition) {
            return ((SpringBootCondition) condition).getMatchOutcome(context, metadata)
                    .isMatch();
        }
        return condition.matches(context, metadata);
    }
}
/**
 *  指定的属性是否定义在此 Environment 中
 */
@Order(Ordered.HIGHEST_PRECEDENCE + 40)
class OnPropertyCondition extends SpringBootCondition {
    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 读取目标元素上所有的 @ConditionalOnProperty 注解的属性信息
        final List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap(
                metadata.getAllAnnotationAttributes(ConditionalOnProperty.class.getName()));
        final List<ConditionMessage> noMatch = new ArrayList<>();
        final List<ConditionMessage> match = new ArrayList<>();
        for (final AnnotationAttributes annotationAttributes : allAnnotationAttributes) {
            // 确定当前 ConditionalOnProperty 条件的输出结果
            final ConditionOutcome outcome = determineOutcome(annotationAttributes, context.getEnvironment());
            // 记录 ConditionMessage
            (outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage());
        }
        // 存在一个不匹配条件
        if (!noMatch.isEmpty()) {
            return ConditionOutcome.noMatch(ConditionMessage.of(noMatch));
        }
        // 所有的条件都匹配
        return ConditionOutcome.match(ConditionMessage.of(match));
    }
    private List<AnnotationAttributes> annotationAttributesFromMultiValueMap(
            MultiValueMap<String, Object> multiValueMap) {
        final List<Map<String, Object>> maps = new ArrayList<>();
        multiValueMap.forEach((key, value) -> {
            for (int i = 0; i < value.size(); i++) {
                Map<String, Object> map;
                if (i < maps.size()) {
                    map = maps.get(i);
                } else {
                    map = new HashMap<>();
                    maps.add(map);
                }
                map.put(key, value.get(i));
            }
        });
        final List<AnnotationAttributes> annotationAttributes = new ArrayList<>(maps.size());
        for (final Map<String, Object> map : maps) {
            annotationAttributes.add(AnnotationAttributes.fromMap(map));
        }
        return annotationAttributes;
    }
    private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes, PropertyResolver resolver) {
        final Spec spec = new Spec(annotationAttributes);
        final List<String> missingProperties = new ArrayList<>();
        final List<String> nonMatchingProperties = new ArrayList<>();
        spec.collectProperties(resolver, missingProperties, nonMatchingProperties);
        // 1)属性值不存在
        if (!missingProperties.isEmpty()) {
            return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnProperty.class, spec)
                    .didNotFind("property", "properties").items(Style.QUOTE, missingProperties));
        }
        // 2)属性值存在,但是不匹配
        if (!nonMatchingProperties.isEmpty()) {
            return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnProperty.class, spec)
                    .found("different value in property", "different value in properties")
                    .items(Style.QUOTE, nonMatchingProperties));
        }
        // 此 ConditionalOnProperty 条件匹配
        return ConditionOutcome
                .match(ConditionMessage.forCondition(ConditionalOnProperty.class, spec).because("matched"));
    }
    private static class Spec {
        private final String prefix;
        private final String havingValue;
        private final String[] names;
        private final boolean matchIfMissing;
        Spec(AnnotationAttributes annotationAttributes) {
            // 读取 ConditionalOnProperty 注解的 prefix 属性
            String prefix = annotationAttributes.getString("prefix").trim();
            // prefix 不为空,则尝试添加 . 后缀
            if (StringUtils.hasText(prefix) && !prefix.endsWith(".")) {
                prefix = prefix + ".";
            }
            this.prefix = prefix;
            // 读取  ConditionalOnProperty 注解的 havingValue 属性
            havingValue = annotationAttributes.getString("havingValue");
            // 读取  ConditionalOnProperty 注解的关联属性名称
            names = getNames(annotationAttributes);
            // 读取 ConditionalOnProperty 注解的 matchIfMissing 属性
            matchIfMissing = annotationAttributes.getBoolean("matchIfMissing");
        }
        private String[] getNames(Map<String, Object> annotationAttributes) {
            final String[] value = (String[]) annotationAttributes.get("value");
            final String[] name = (String[]) annotationAttributes.get("name");
            Assert.state(value.length > 0 || name.length > 0,
                    "The name or value attribute of @ConditionalOnProperty must be specified");
            Assert.state(value.length == 0 || name.length == 0,
                    "The name and value attributes of @ConditionalOnProperty are exclusive");
            // value 属性的优先级高于 name
            return value.length > 0 ? value : name;
        }
        private void collectProperties(PropertyResolver resolver, List<String> missing, List<String> nonMatching) {
            // 遍历所有的属性名称
            for (final String name : names) {
                // 添加前缀
                final String key = prefix + name;
                // 1)如果 Environment 中存在此属性
                if (resolver.containsProperty(key)) {
                    // 指定的值不匹配,则写入 nonMatching 中
                    if (!isMatch(resolver.getProperty(key), havingValue)) {
                        nonMatching.add(name);
                    }
                    // 2)Environment 中不存在此属性
                } else {
                    // 如果不能忽略此属性,则写入 missing 中
                    if (!matchIfMissing) {
                        missing.add(name);
                    }
                }
            }
        }
        private boolean isMatch(String value, String requiredValue) {
            // 1)指定了必须的值,则使用 equals 进行比较
            if (StringUtils.hasLength(requiredValue)) {
                return requiredValue.equalsIgnoreCase(value);
            }
            // 只要属性值不是忽略大小写的 false,就匹配
            return !"false".equalsIgnoreCase(value);
        }
        @Override
        public String toString() {
            final StringBuilder result = new StringBuilder();
            result.append("(");
            result.append(prefix);
            if (names.length == 1) {
                result.append(names[0]);
            } else {
                result.append("[");
                result.append(StringUtils.arrayToCommaDelimitedString(names));
                result.append("]");
            }
            if (StringUtils.hasLength(havingValue)) {
                result.append("=").append(havingValue);
            }
            result.append(")");
            return result.toString();
        }
    }
}

3.4 loadBeanDefinitions加载bean定义信息

ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()方法的功能就是将之前解析出的configClasses配置类信息中所有配置相关的信息添加到spring的bean定义,主要是配置类中的@Bean注解方法,配置类@ImportResource和@Import(实现ImportBeanDefinitionRegistrar接口方式)的bean注册
ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()方法 实现逻辑如下:

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
   TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
   for (ConfigurationClass configClass : configurationModel) {
      loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
   }
}

处理逻辑理了一遍后,看一下ConfigurationClassPostProcessor处理器解析@configuration配置类主要过程:
1. Spring容器初始化时注册默认后置处理器ConfigurationClassPostProcessor
2. Spring容器初始化执行refresh()方法中调用ConfigurationClassPostProcessor
3. ConfigurationClassPostProcessor处理器借助ConfigurationClassParser完成配置类解析
4. ConfigurationClassParser配置内解析过程中完成嵌套的MemberClass、@PropertySource注解、@ComponentScan注解(扫描package下的所有Class并进行迭代解析,主要是@Component组件解析及注册)、@ImportResource、@Bean等处理
5. 完成@Bean注册, @ImportResource指定bean的注册以及@Import(实现ImportBeanDefinitionRegistrar接口方式)的bean注册

4 总结

扫描Bean的顺序(并不是Bean定义真正注册的顺序):

  1. 内部配置类:–> 它里面还可以有普通配置类一模一样的功能,但优先级最高,最终会放在configurationClasses这个Map的第一位
  2. @PropertySource:这个和Bean定义没啥关系,属于Spring配置PropertySource的范畴。这个属性优先级相对较低
  3. @ComponentScan:这里扫描到的Bean定义,就直接register注册了。所以它的时机是非常早的。(另外:如果注册进去的Bean定义信息还是配置类,这里会继续parse(),所以最终能被扫描到的组件,最终都会当作一个配置类来处理,所以最终都会放进configurationClasses这个Map里面去)
  4. @Import:相对复杂点,如下:
    1. 若是一个普通类(标注@Configuration与否都无所谓反正会当作一个配置类来处理,也会放进configurationClasses缓存进去)
    2. 实现了ImportSelector:递归最后都成为第一步的类。若实现的是DeferredImportSelector接口,它会放在deferredImportSelectors属性里先保存着,等着外部所有的configCandidates配置类全部解析完成后,统一processDeferredImportSelectors(),最终也是转为第一步的类。
    3. 实现了ImportBeanDefinitionRegistrar:放在ConfigurationClass.importBeanDefinitionRegistrars属性里保存着
  5. @ImportResource:一般用来导入xml文件。它是先放在ConfigurationClass.importedResources属性里放着
  6. @Bean:找到所有@Bean的方法,然后保存到ConfigurationClass.beanMethods属性里
  7. processInterfaces:处理该类实现的接口们的default方法(标注@Bean的有效)
  8. 处理父类:拿到父类,每个父类都是当作一个配置文件来处理。备注:!superclass.startsWith(“java”)全类名不以java打头,且没有被处理过(因为一个父类可以有N个子类,但只能被处理一次)
  9. return null:若全部处理完成后就返回null,停止递归。

由上可见,这九步中,唯独只有@ComponentScan扫描到的Bean这个时候的Bean定义信息是已经注册上去了的,其余的都还没有真正注册到注册中心。
注意:bean注册的先后顺序,将直接影响到Bean的覆盖(默认Map,后注册的覆盖先注册的,当然还和scope有关)

作者:模范青蛙

来源:https://segmentfault.com/a/1190000020625414


版权声明:文末如注明作者和来源,则表示本文系转载,版权为原作者所有 | 本文如有侵权,请及时联系,承诺在收到消息后第一时间删除 | 如转载本文,请注明原文链接。
喜欢 (0)