Spring EnableAutoConfigurationImportSelector 是如何工作的 ?

41 篇文章 1 订阅
17 篇文章 0 订阅

https://blog.csdn.net/andy_zhang2007/article/details/78580980

功能

EnableAutoConfigurationImportSelector 是一个DeferredImportSelector,由 spring boot autoconfigure 从版本1.3开始,提供用来处理EnableAutoConfiguration自动配置。

EnableAutoConfigurationImportSelector继承自AutoConfigurationImportSelector,从 spring boot 1.5 以后,EnableAutoConfigurationImportSelector已经不再被建议使用,而是推荐使用 AutoConfigurationImportSelector。
何时被引入

Spring boot应用中使用了注解@SpringBootApplication,该注解隐含地导入了EnableAutoConfigurationImportSelector,如下注解依赖链所示 :

// 注解链
@SpringBootApplication
    => @EnableAutoConfiguration
        => @Import(EnableAutoConfigurationImportSelector.class)

    1
    2
    3
    4

何时被执行

Springboot应用启动过程中使用ConfigurationClassParser分析配置类时,如果发现注解中存在@Import(ImportSelector)的情况,就会创建一个相应的ImportSelector对象, 并调用其方法 public String[] selectImports(AnnotationMetadata annotationMetadata), 这里 EnableAutoConfigurationImportSelector的导入@Import(EnableAutoConfigurationImportSelector.class) 就属于这种情况,所以ConfigurationClassParser会实例化一个 EnableAutoConfigurationImportSelector 并调用它的 selectImports() 方法。

    // selectImports 的具体执行逻辑
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        try {
            // 从配置文件中加载 AutoConfigurationMetadata
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                    .loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = getAttributes(annotationMetadata);
            // 获取所有候选配置类EnableAutoConfiguration
            // 使用了内部工具使用SpringFactoriesLoader,查找classpath上所有jar包中的
            // META-INF\spring.factories,找出其中key为
            // org.springframework.boot.autoconfigure.EnableAutoConfiguration
            // 的属性定义的工厂类名称。
            // 虽然参数有annotationMetadata,attributes,但在 AutoConfigurationImportSelector 的
            // 实现 getCandidateConfigurations()中,这两个参数并未使用
            List<String> configurations = getCandidateConfigurations(annotationMetadata,
                    attributes);
            // 去重                    
            configurations = removeDuplicates(configurations);
            // 排序 : 先按字典序,再按order属性,再考虑注解  @AutoConfigureBefore @AutoConfigureAfter
            configurations = sort(configurations, autoConfigurationMetadata);
            // 应用 exclusion 属性
            Set<String> exclusions = getExclusions(annotationMetadata, attributes);
            checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            // 应用过滤器AutoConfigurationImportFilter,
            // 对于 spring boot autoconfigure,定义了一个需要被应用的过滤器 :
            // org.springframework.boot.autoconfigure.condition.OnClassCondition,
            // 此过滤器检查候选配置类上的注解@ConditionalOnClass,如果要求的类在classpath
            // 中不存在,则这个候选配置类会被排除掉
            configurations = filter(configurations, autoConfigurationMetadata);
            // 现在已经找到所有需要被应用的候选配置类
            // 广播事件 AutoConfigurationImportEvent
            fireAutoConfigurationImportEvents(configurations, exclusions);
            return configurations.toArray(new String[configurations.size()]);
        }
        catch (IOException ex) {
            throw new IllegalStateException(ex);
        }
    }
    /**
     * Return the auto-configuration class names that should be considered. By default
     * this method will load candidates using SpringFactoriesLoader with
     * getSpringFactoriesLoaderFactoryClass().
     * @param metadata the source metadata
     * @param attributes the getAttributes(AnnotationMetadata) annotation
     * attributes
     * @return a list of candidate configurations
     */
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
            AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
                getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
        Assert.notEmpty(configurations,
                "No auto configuration classes found in META-INF/spring.factories. If you "
                        + "are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

    /**
     * Return the class used by SpringFactoriesLoader to load configuration
     * candidates.
     * @return the factory class
     */
    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }    
    /**
      * 根据autoConfigurationMetadata信息对候选配置类configurations进行过滤
      **/
    private List<String> filter(List<String> configurations,
            AutoConfigurationMetadata autoConfigurationMetadata) {
        long startTime = System.nanoTime();
        String[] candidates = configurations.toArray(new String[configurations.size()]);
        // 记录候选配置类是否需要被排除,skip为true表示需要被排除,全部初始化为false,不需要被排除
        boolean[] skip = new boolean[candidates.length];
        // 记录候选配置类中是否有任何一个候选配置类被忽略,初始化为false
        boolean skipped = false;
        // 获取AutoConfigurationImportFilter并逐个应用过滤
        for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
            // 对过滤器注入其需要Aware的信息
            invokeAwareMethods(filter);
            // 使用此过滤器检查候选配置类跟autoConfigurationMetadata的匹配情况
            boolean[] match = filter.match(candidates, autoConfigurationMetadata);
            for (int i = 0; i < match.length; i++) {
                if (!match[i]) {
                // 如果有某个候选配置类不符合当前过滤器,将其标记为需要被排除,
                // 并且将 skipped设置为true,表示发现了某个候选配置类需要被排除
                    skip[i] = true;
                    skipped = true;
                }
            }
        }
        if (!skipped) {
        // 如果所有的候选配置类都不需要被排除,则直接返回外部参数提供的候选配置类集合
            return configurations;
        }
        // 逻辑走到这里因为skipped为true,表明上面的的过滤器应用逻辑中发现了某些候选配置类
        // 需要被排除,这里排除那些需要被排除的候选配置类,将那些不需要被排除的候选配置类组成
        // 一个新的集合返回给调用者
        List<String> result = new ArrayList<String>(candidates.length);
        for (int i = 0; i < candidates.length; i++) {
            if (!skip[i]) {
                result.add(candidates[i]);
            }
        }
        if (logger.isTraceEnabled()) {
            int numberFiltered = configurations.size() - result.size();
            logger.trace("Filtered " + numberFiltered + " auto configuration class in "
                    + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)
                    + " ms");
        }
        return new ArrayList<String>(result);
    }    
    /**
      * 使用内部工具 SpringFactoriesLoader,查找classpath上所有jar包中的
      * META-INF\spring.factories,找出其中key为
      * org.springframework.boot.autoconfigure.AutoConfigurationImportFilter
      * 的属性定义的过滤器类并实例化。
      * AutoConfigurationImportFilter过滤器可以被注册到 spring.factories用于对自动配置类
      * 做一些限制,在这些自动配置类的字节码被读取之前做快速排除处理。
      * spring boot autoconfigure 缺省注册了一个 AutoConfigurationImportFilter :
      * org.springframework.boot.autoconfigure.condition.OnClassCondition
    **/
    protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
        return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
                this.beanClassLoader);
    }    

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131

相关文章

Spring 工具类 ConfigurationClassParser 是如何工作的 ?
Springboot 的内部工具类 SpringFactoriesLoader
---------------------
作者:九九八八
来源:CSDN
原文:https://blog.csdn.net/andy_zhang2007/article/details/78580980
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值