SpringBoot自动配置原理
一、相关的几个注解
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {}
- 通常在启动类上使用 @SpringBootApplication
- 表明此类是配置类 + 启用自动配置 + 包扫描
- @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 中,但是主动排除的放入了
排除
-
EnableAutoConfiguration 注解中的 exclude 属性和 excludeName 属性
-
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()); } // ... } }
三、总的涉及到的知识点
- Spring的SPI:META-INF/spring.factories
- @Import的处理
- DeferredImportSelector的处理