SpringBoot 自动配置原理(三)

时间:2021-07-08
本文章向大家介绍SpringBoot 自动配置原理(三),主要包括SpringBoot 自动配置原理(三)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

上一篇文章中,我们提到AutoConfigurationImportSelector.AutoConfigurationGroup#process会将classpath下所有的META-INFO/spring.factories中的org.springframework.boot.autoconfigure.EnableAutoConfiguration属性中的自动配置类读取进来。spring.factories中声明的自动装配类非常的多,难道我们每一个自动配置类都需要处理吗?答案当然是否定的,这篇文章来探讨一下SpringBoot是如何过滤掉不需要自动配置的类的。

AutoConfigurationImportSelector#getAutoConfigurationEntry

先来回顾一下方法getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    //读取spring.factories中的自动配置类
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    configurations = removeDuplicates(configurations);
    //读取@SpringBootApplication中excluded声明的要排除的自动配置类
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    //过滤不需要装配的自动配置类
    configurations = getConfigurationClassFilter().filter(configurations);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}

这里的关键就在这个filter()方法中。

List<String> filter(List<String> configurations) {
    long startTime = System.nanoTime();
    String[] candidates = StringUtils.toStringArray(configurations);
    boolean skipped = false;
    //这里的filters其实是对@Conditional系列注解进行判断
    //这里进行断点的话可以发现filters中是三个类,OnClassCondition\OnBeanCondition\OnWebApplicationCondition
    for (AutoConfigurationImportFilter filter : this.filters) {
        boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
        for (int i = 0; i < match.length; i++) {
            if (!match[i]) {
                candidates[i] = null;
                skipped = true;
            }
        }
    }
    if (!skipped) {
        return configurations;
    }
    List<String> result = new ArrayList<>(candidates.length);
    for (String candidate : candidates) {
        if (candidate != null) {
            result.add(candidate);
        }
    }
    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 result;
}

@Conditional

我们任意点进一个spring.factories中的自动配置类,我们或多或少的可以看到如@ConditionalOnClass这样的注解,上面讲到的filter()方法就会对这些@Conditional注解进行过滤。这里简单介绍几个常见的@Conditional注解

  • @ConditionalOnClass

    这个注解用于判断某个类是否存在于classpath中,如果存在则进行自动配置。

  • @ConditionalOnBean

    这个注解用于判断某个Bean是否存在于IoC容器中,如果存在则进行自动配置。

  • @ConditionalOnMissingClass

    这个注解用于判断某个类是否存在于classpath中,如果存在则进行自动配置。

  • @ConditionalOnMissingBean

    这个注解用于判断某个Bean是否存在于IoC容器中,如果存在则进行自动配置。

经过过滤之后SpringBoot就会得到一个确定需要自动配置的类的全限定类名列表,之后的工作就交给Spring来完成了。

总结

spring.factories中的自动配置类并不是都需要自动配置,会通过在类上标注@Conditional注解的方式来告诉SpringBoot哪些类满足自动配置的需求,最后将经过过滤的自动配置类交给Spring来解析。

原文地址:https://www.cnblogs.com/supermaskv/p/14988658.html