1. 程式人生 > 其它 >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來解析。