@EnableAutoConfiguration自动装配注解的语义实现。

注解定义

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Inherited
  4. @AutoConfigurationPackage
  5. // 导入实现AutoConfigurationImportSelector
  6. @Import(AutoConfigurationImportSelector.class)
  7. public @interface EnableAutoConfiguration {
  8. // 可通过环境变量关闭自动配置
  9. String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
  10. Class<?>[] exclude() default {};
  11. String[] excludeName() default {};
  12. }

在Spring扫描加载类过程中会执行AutoConfigurationImportSelector中的相关方法,AutoConfigurationImportSelector实现了Spring的DeferredImportSelector就会在ConfigurationClassParse类中得到解析并回调相关接口方法

ConfigurationClassParser中解析ImportSelector

在Bean扫描过程中有解析DeferredImportSelector实现的逻辑:

  1. // ConfigurationClassParser
  2. for (DeferredImportSelectorGrouping grouping : groupings.values()) {
  3. // grouping.getImports()获取导入的配置类
  4. grouping.getImports().forEach((entry) -> {
  5. ConfigurationClass configurationClass = configurationClasses.get(
  6. entry.getMetadata());
  7. try {
  8. processImports(configurationClass, asSourceClass(configurationClass),
  9. asSourceClasses(entry.getImportClassName()), false);
  10. }
  11. catch (BeanDefinitionStoreException ex) {
  12. throw ex;
  13. }
  14. catch (Throwable ex) {
  15. throw new BeanDefinitionStoreException(
  16. "Failed to process import candidates for configuration class [" +
  17. configurationClass.getMetadata().getClassName() + "]", ex);
  18. }
  19. });
  20. }
  21. // 执行DeferredImportSelector中的钩子方法
  22. public Iterable<Group.Entry> getImports() {
  23. for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
  24. this.group.process(deferredImport.getConfigurationClass().getMetadata(),
  25. deferredImport.getImportSelector());
  26. }
  27. return this.group.selectImports();
  28. }

钩子方法AutoConfigurationGroup#process实现

AutoConfigurationImportSelector中定义内部类AutoConfigurationGroup

  1. private static class AutoConfigurationGroup implements DeferredImportSelector.Group,
  2. BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
  3. private ClassLoader beanClassLoader;
  4. private BeanFactory beanFactory;
  5. private ResourceLoader resourceLoader;
  6. private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>();
  7. // 被调用的钩子方法
  8. @Override
  9. public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
  10. // AutoConfigurationImportSelector#selectImports
  11. // 还是调用了ImportSelector来处理获取需要加载自动装配的配置类
  12. String[] imports = deferredImportSelector.selectImports(annotationMetadata);
  13. for (String importClassName : imports) {
  14. // 存起来,调用DeferredImportSelector.Group#selectImports时返回
  15. this.entries.put(importClassName, annotationMetadata);
  16. }
  17. }
  18. @Override
  19. public Iterable<Entry> selectImports() {
  20. // 返回排序后的导入配置类
  21. return sortAutoConfigurations().stream()
  22. .map((importClassName) -> new Entry(this.entries.get(importClassName),
  23. importClassName))
  24. .collect(Collectors.toList());
  25. }
  26. private List<String> sortAutoConfigurations() {
  27. // 排序
  28. List<String> autoConfigurations = new ArrayList<>(this.entries.keySet());
  29. if (this.entries.size() <= 1) {
  30. return autoConfigurations;
  31. }
  32. // 超过1个时排序
  33. AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
  34. .loadMetadata(this.beanClassLoader);
  35. //
  36. return new AutoConfigurationSorter(getMetadataReaderFactory(),autoConfigurationMetadata)
  37. .getInPriorityOrder(autoConfigurations);
  38. }
  39. private MetadataReaderFactory getMetadataReaderFactory() {
  40. try {
  41. return this.beanFactory.getBean(
  42. SharedMetadataReaderFactoryContextInitializer.BEAN_NAME,
  43. MetadataReaderFactory.class);
  44. } catch (NoSuchBeanDefinitionException ex) {
  45. return new CachingMetadataReaderFactory(this.resourceLoader);
  46. }
  47. }
  48. }

在方法中最终还是调用了deferredImportSelector.selectImports(annotationMetadata);进一步获取需要自动装配的配置类。我们继续看AutoConfigurationImportSelector

AutoConfigurationImportSelector

public class AutoConfigurationImportSelector
        implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
        BeanFactoryAware, EnvironmentAware, Ordered {
    private static final String[] NO_IMPORTS = {};
    private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
    // 容器上下文相关
    private ConfigurableListableBeanFactory beanFactory;
    private Environment environment;
    private ClassLoader beanClassLoader;
    private ResourceLoader resourceLoader;
}

ImportSelector#selectImports()的实现
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    }
    // 这里用AutoConfigurationMetadataLoader
    // 加载所有jar包中的 META-INF/spring-autoconfigure-metadata.properties 文件
    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
            .loadMetadata(this.beanClassLoader);
    // 
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 加载所有jar包中的spring.factories
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 去重
    configurations = removeDuplicates(configurations);
    // 排除注解指定排除的类
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    // 过滤
    configurations = filter(configurations, autoConfigurationMetadata);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    // 返回最终需要自动装配的配置类
    return StringUtils.toStringArray(configurations);
}

这里主要完成SPI配置文件的加载解析:

  1. spring-autoconfigure-metadata.properties的加载及解析
  2. spring.factories文件的加载及解析,参见
  3. 根据配置规则进行解析过滤,得到最终的自动装载配置类

spring-autoconfigure-metadata.properties文件的加载及作用
final class AutoConfigurationMetadataLoader {
    protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";

    public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
        return loadMetadata(classLoader, PATH);
    }
    // 加载所有jar包中的指定文件
    static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
        try {
            Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(path) : ClassLoader.getSystemResources(path));
            Properties properties = new Properties();
            while (urls.hasMoreElements()) {
                // 放入容器中
                properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
            }
            // 包装一下
            return loadMetadata(properties);
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
        }
    }
}

看看spring-autoconfigure-metadata.properties的配置内容格式

org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration=
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration.Configuration=
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,org.springframework.data.cassandra.core.ReactiveCassandraTemplate,reactor.core.publisher.Flux
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration.ConditionalOnClass=org.apache.solr.client.solrj.SolrClient,org.springframework.data.solr.repository.SolrRepository
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration=
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration=
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration.Configuration=

例如:org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration.ConditionalOnClass = org.apache.solr.client.solrj.SolrClient,org.springframework.data.solr.repository.SolrRepository
这条配置表SolrRepositoriesAutoConfiguration这个类的加载需要ClassPath下存在SolrRepository这个类。

再然后就是加载spring.factories这个配置文件中的内容,getCandidateConfigurations(annotationMetadata, attributes);这里定义了全部可能被加载的配置类,参见
接着对加载进来的配置类进行过滤

configurations = filter(configurations, autoConfigurationMetadata);
private List<String> filter(List<String> configurations,
        AutoConfigurationMetadata autoConfigurationMetadata) {
    long startTime = System.nanoTime();
    String[] candidates = StringUtils.toStringArray(configurations);
    boolean[] skip = new boolean[candidates.length];
    boolean skipped = false;
    // SPI 加载过滤器
    for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
        // 属性设置
        invokeAwareMethods(filter);
        // 匹配方法调用
        boolean[] match = filter.match(candidates, autoConfigurationMetadata);
        for (int i = 0; i < match.length; i++) {
            if (!match[i]) {
                skip[i] = true;
                skipped = true;
            }
        }
    }

    if (!skipped) {
        return configurations;
    }

    List<String> result = new ArrayList<>(candidates.length);
    for (int i = 0; i < candidates.length; i++) {
        if (!skip[i]) {
            result.add(candidates[i]);
        }
    }
    // 返回符合条件的
    return new ArrayList<>(result);
}

protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
    // 加载配置的条件评估工具
    return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
            this.beanClassLoader);
}

这里的filter过滤条件是根据spring-autoconfigure-metadata.properties这个配置文件中的条件过滤的,在Spring扫描BeanDefinition时定义了@Conditional强大的条件功能配置时还提前搞这么复杂的配置过滤方式就是为了提高过滤速度,减小启动时间。
AutoConfigurationImportFilter接口的实现在SpringBoot中有唯一的实现OnClassCondition,有兴趣时可以去具体学习分析。