一、概述
AutoConfigurationImportSelector 是 Spring Boot 自动配置机制的核心组件之一,它负责在应用启动时自动发现、加载和筛选需要生效的自动配置类。这个类实现了 DeferredImportSelector 接口,采用延迟导入策略,确保自动配置类在其他配置类处理完成后再进行导入。
二、类的职责与接口实现
2.1 核心接口
AutoConfigurationImportSelector 实现了以下关键接口:
DeferredImportSelector:延迟导入选择器,允许在配置类处理完成后才导入自动配置类BeanClassLoaderAware:获取 Bean 类加载器ResourceLoaderAware:获取资源加载器BeanFactoryAware:获取 Bean 工厂EnvironmentAware:获取环境配置Ordered:定义执行顺序(值为2147483646,优先级较低)
2.2 主要职责
- 从
META-INF/spring.factories文件中加载自动配置类列表 - 对自动配置类进行去重处理
- 根据排除规则移除不需要的配置类
- 通过过滤器进行条件筛选
- 触发自动配置导入事件
三、从 spring.factories 获取自动配置类列表
3.1 核心方法:getCandidateConfigurations
java
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
this.getSpringFactoriesLoaderFactoryClass(),
this.getBeanClassLoader()
);
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. " +
"If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
3.2 工作原理
-
指定工厂类类型:
getSpringFactoriesLoaderFactoryClass()返回EnableAutoConfiguration.class- 这告诉
SpringFactoriesLoader要查找哪个键对应的配置类列表
-
加载机制:
SpringFactoriesLoader.loadFactoryNames()会扫描所有 jar 包中的META-INF/spring.factories文件- 查找键为
org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置 - 返回所有符合条件的自动配置类的全限定名列表
-
典型的 spring.factories 文件格式:
properties
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.AutoConfiguration1,\
com.example.AutoConfiguration2,\
...
3.3 获取流程
less
@EnableAutoConfiguration 注解
↓
AutoConfigurationImportSelector.selectImports()
↓
getAutoConfigurationEntry()
↓
getCandidateConfigurations()
↓
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, classLoader)
↓
扫描所有 META-INF/spring.factories 文件
↓
返回自动配置类全限定名列表
四、自动配置类的筛选和过滤机制
自动配置类的筛选和过滤是一个多步骤的过程,在 getAutoConfigurationEntry 方法中完成:
java
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 1. 获取注解属性
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 2. 获取候选配置类列表
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// 3. 去重
configurations = this.removeDuplicates(configurations);
// 4. 获取排除列表
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
// 5. 检查排除类的有效性
this.checkExcludedClasses(configurations, exclusions);
// 6. 移除排除的配置类
configurations.removeAll(exclusions);
// 7. 条件过滤
configurations = this.filter(configurations, autoConfigurationMetadata);
// 8. 触发导入事件
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
4.1 步骤一:去重处理
java
protected final <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList(new LinkedHashSet(list));
}
- 使用
LinkedHashSet去除重复的配置类 - 保持原有的顺序(
LinkedHashSet是有序的)
4.2 步骤二:排除机制
排除机制通过 getExclusions 方法收集所有需要排除的配置类:
java
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet();
// 1. 从注解的 exclude 属性获取(类对象)
excluded.addAll(this.asList(attributes, "exclude"));
// 2. 从注解的 excludeName 属性获取(类名)
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
// 3. 从配置属性 spring.autoconfigure.exclude 获取
excluded.addAll(this.getExcludeAutoConfigurationsProperty());
return excluded;
}
排除来源:
-
注解属性 exclude:
java@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) -
注解属性 excludeName:
java@EnableAutoConfiguration(excludeName = {"com.example.SomeAutoConfiguration"}) -
配置文件属性:
propertiesspring.autoconfigure.exclude=com.example.AutoConfiguration1,com.example.AutoConfiguration2
有效性检查:
java
private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
List<String> invalidExcludes = new ArrayList(exclusions.size());
for (String exclusion : exclusions) {
// 如果类存在但不在配置列表中,说明排除无效
if (ClassUtils.isPresent(exclusion, this.getClass().getClassLoader())
&& !configurations.contains(exclusion)) {
invalidExcludes.add(exclusion);
}
}
if (!invalidExcludes.isEmpty()) {
this.handleInvalidExcludes(invalidExcludes);
}
}
4.3 步骤三:条件过滤(核心机制)
filter 方法是自动配置类筛选的核心,它使用 AutoConfigurationImportFilter 进行条件判断:
java
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;
// 获取所有过滤器
Iterator<AutoConfigurationImportFilter> iterator =
this.getAutoConfigurationImportFilters().iterator();
while (iterator.hasNext()) {
AutoConfigurationImportFilter filter = iterator.next();
// 注入依赖(Aware 接口)
this.invokeAwareMethods(filter);
// 执行过滤匹配
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
// 标记需要跳过的配置类
for (int i = 0; i < match.length; ++i) {
if (!match[i]) {
skip[i] = true;
candidates[i] = null;
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]);
}
}
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 new ArrayList(result);
}
过滤器获取:
java
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(
AutoConfigurationImportFilter.class,
this.beanClassLoader
);
}
过滤器同样通过 spring.factories 加载,典型的过滤器包括:
OnClassCondition:检查类路径中是否存在指定的类OnBeanCondition:检查容器中是否存在指定的 BeanOnWebApplicationCondition:检查是否为 Web 应用
过滤器工作原理:
- 每个过滤器对候选配置类数组进行匹配
- 返回一个
boolean[]数组,true表示匹配(保留),false表示不匹配(过滤) - 所有过滤器的结果进行逻辑与运算(所有过滤器都通过才保留)
示例:OnClassCondition 过滤器
java
// 伪代码示例
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata metadata) {
boolean[] match = new boolean[autoConfigurationClasses.length];
for (int i = 0; i < autoConfigurationClasses.length; i++) {
String className = autoConfigurationClasses[i];
// 检查 @ConditionalOnClass 注解
// 如果类路径中不存在必需的类,则返回 false
match[i] = checkRequiredClassesExist(className);
}
return match;
}
4.4 步骤四:触发导入事件
java
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
List<AutoConfigurationImportListener> listeners =
this.getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
AutoConfigurationImportEvent event =
new AutoConfigurationImportEvent(this, configurations, exclusions);
for (AutoConfigurationImportListener listener : listeners) {
this.invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
}
}
}
允许其他组件监听自动配置导入过程,进行额外的处理。
五、延迟导入机制(DeferredImportSelector)
5.1 AutoConfigurationGroup 内部类
AutoConfigurationImportSelector 实现了 getImportGroup 方法,返回 AutoConfigurationGroup:
java
public Class<? extends DeferredImportSelector.Group> getImportGroup() {
return AutoConfigurationGroup.class;
}
5.2 延迟导入的优势
- 优先级控制:确保自动配置类在其他配置类之后处理
- 条件评估:在 Bean 定义完成后,条件注解能更准确地评估
- 性能优化:避免不必要的类加载和条件检查
5.3 排序机制
在 AutoConfigurationGroup.selectImports() 中,会对配置类进行排序:
java
private List<String> sortAutoConfigurations(
Set<String> configurations,
AutoConfigurationMetadata autoConfigurationMetadata) {
return (new AutoConfigurationSorter(
this.getMetadataReaderFactory(),
autoConfigurationMetadata
)).getInPriorityOrder(configurations);
}
排序依据:
@AutoConfigureBefore注解@AutoConfigureAfter注解@AutoConfigureOrder注解- 依赖关系
六、完整流程图
less
应用启动
↓
@EnableAutoConfiguration 注解被处理
↓
AutoConfigurationImportSelector.selectImports()
↓
┌─────────────────────────────────────┐
│ getAutoConfigurationEntry() │
│ │
│ 1. 检查是否启用自动配置 │
│ 2. 从 spring.factories 加载候选类 │
│ 3. 去重 │
│ 4. 获取排除列表 │
│ 5. 移除排除的配置类 │
│ 6. 条件过滤(OnClassCondition等) │
│ 7. 触发导入事件 │
└─────────────────────────────────────┘
↓
返回最终配置类列表
↓
Spring 容器加载这些配置类
↓
自动配置生效