SpringBoot自动配置原理

一、相关的几个注解

 

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}
  1. 通常在启动类上使用 @SpringBootApplication
  2. 表明此类是配置类 + 启用自动配置 + 包扫描
  3. @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan

 

 

 

二、@EnableAutoConfiguration

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

 

简单AutoConfigurationImportSelector#selectImports流程

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 可以命令行配置禁止自动配置 spring.boot.enableautoconfiguration
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        // 找到所有自动配置类, 过滤器处理 + 排除处理, AutoConfigurationEntry 封装了所有需要配置的和排除的
        AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
        // 得到需要配置的全部类
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
    
    
    protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        }
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        // 获取 META-INF/spring.factories EnableAutoConfiguration 配置列表
        List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        // 去重(转Set再转List)
        configurations = removeDuplicates(configurations);
        // 要排除的自动配置类
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        // 校验, 若配置了排除不在 configurations 中的类则抛出异常
        checkExcludedClasses(configurations, exclusions);
        // 排除
        configurations.removeAll(exclusions);
        // 过滤器列表, 过滤, META-INF/spring.factories 内的 AutoConfigurationImportFilter 配置
        // 过滤器处理后返回的列表可能有些类已经被排除了
        configurations = getConfigurationClassFilter().filter(configurations);
        // emm, META-INF/spring.factories 内的 AutoConfigurationImportListener 配置, 事件调用, configurations 是所有会自动配置的类
        fireAutoConfigurationImportEvents(configurations, exclusions);
        // 封装要自动配置的类 configurations + 排除的类 exclusions
        return new AutoConfigurationEntry(configurations, exclusions);
    }

这里不太理解,过滤器过滤掉的配置类没有放入 exclusions 中,但是主动排除的放入了

排除

  1. EnableAutoConfiguration 注解中的 exclude 属性和 excludeName 属性
  2. spring.autoconfigure.exclude 参数配置要排除的(命令行配置等)

 

 

上面的 selectImports 实际不会被调用,因为 AutoConfigurationImportSelector 是 DeferredImportSelector 实现类,特殊处理的,看一些内部类

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
        ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {}
        
        
    // 返回处理当前 DeferredImportSelector 的 Group 类型
    @Override
    public Class<? extends Group> getImportGroup() {
        return AutoConfigurationGroup.class;
    }
    
    // AutoConfigurationImportSelector 的内部类
    // 也继承了许多接口, 创建当前 Group 实例时也会回调这些 Aware 接口
    private static class AutoConfigurationGroup
            implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {

        private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>();

        private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>();

        private ClassLoader beanClassLoader;

        private BeanFactory beanFactory;

        private ResourceLoader resourceLoader;

        private AutoConfigurationMetadata autoConfigurationMetadata;

        // 接口回调 setter


        // 1. 会先调用 process
        //   --> 会使用一个 Group 实例处理它能处理的一系列 DeferredImportSelector 实例
        //     --> 每一个 DeferredImportSelector 实例都可以注入数据, 现在还未注入, 仅缓存起来
        @Override
        public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
            // 只处理 AutoConfigurationImportSelector
            // 说明这个 Group 仅处理这个类型的实例, 其他类型的 DeferredImportSelector 不处理
            Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
                    () -> String.format("Only %s implementations are supported, got %s",
                            AutoConfigurationImportSelector.class.getSimpleName(),
                            deferredImportSelector.getClass().getName()));
            // AutoConfigurationEntry 包装了要注入的自动配置类和排除了的配置类
            AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
                    .getAutoConfigurationEntry(annotationMetadata);
            this.autoConfigurationEntries.add(autoConfigurationEntry);
            // 遍历需要注入的配置类
            for (String importClassName : autoConfigurationEntry.getConfigurations()) {
                // 配置类全类名 -> 导入此配置类的类的注解信息
                this.entries.putIfAbsent(importClassName, annotationMetadata);
            }
            
            // 注意上面只是将要注入的数据缓存在了当前 Group 实例中
        }

        // 2. 调用它, 返回处理了的所有 DeferredImportSelector 实例要注入的数据
        @Override
        public Iterable<Entry> selectImports() {
            if (this.autoConfigurationEntries.isEmpty()) {
                return Collections.emptyList();
            }
            // 移除的配置类 Set
            Set<String> allExclusions = this.autoConfigurationEntries.stream()
                    .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
            // 要注入的配置类 Set
            Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
                    .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
                    .collect(Collectors.toCollection(LinkedHashSet::new));
            // emm
            processedConfigurations.removeAll(allExclusions);

            // 排序
            return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
                    .map((importClassName) ->
                            // 导入此配置类的类的注解信息为 + 当前被自动注入的类
                            new Entry(this.entries.get(importClassName), importClassName))
                    .collect(Collectors.toList());
        }

        // ...

    }
    
}

 

 

 

 

三、总的涉及到的知识点

  1. Spring的SPI:META-INF/spring.factories
  2. @Import的处理
  3. DeferredImportSelector的处理

 

posted @ 2021-10-22 20:36  YangDanMua  阅读(193)  评论(0编辑  收藏  举报