自动配置类的加载过滤排序全流程
概述
Spring Boot 自动配置的核心引擎是 AutoConfigurationImportSelector——它负责从 AutoConfiguration.imports 文件中读取所有自动配置类候选,经过排除、过滤、排序、分组四个阶段后,将符合条件的配置类注册到 Spring 容器中。
本文将逐个拆解自动配置加载全流程的 9 个关键细节点,涵盖从文件读取到 BeanDefinition 注册的完整路径。
本文基于 Spring Boot 3.x 源码分析。
1. 整体流程
AutoConfigurationImportSelector.selectImports()
│
└─ getAutoConfigurationEntry()
│
├─ 1. getCandidateConfigurations()
│ └─ ImportCandidates.load(AutoConfiguration.class)
│ └─ 读取 AutoConfiguration.imports 文件
│
├─ 2. removeDuplicates() ← LinkedHashSet 去重
│
├─ 3. getExclusions() ← 合并排除列表
│ ├─ @EnableAutoConfiguration(exclude=...)
│ ├─ @EnableAutoConfiguration(excludeName=...)
│ └─ spring.autoconfigure.exclude 属性
│
├─ 4. filter() ← 条件过滤
│ └─ ConfigurationClassFilter.match()
│ ├─ OnClassCondition
│ ├─ OnBeanCondition
│ ├─ OnWebApplicationCondition
│ └─ OnPropertyCondition
│
├─ 5. AutoConfigurationGroup.process() ← 分组排序
│ └─ AutoConfigurationSorter.getInPriorityOrder()
│ └─ 拓扑排序 (before/after/order)
│
└─ 6. 返回 AutoConfigurationEntry
└─ configurations + exclusions2. AutoConfiguration.imports 文件加载
2.1 加载源码
// AutoConfigurationImportSelector.java
protected List<String> getCandidateConfigurations(
AnnotationMetadata metadata, AnnotationAttributes attributes) {
// Spring Boot 3.x 使用 ImportCandidates 替代 SpringFactoriesLoader
List<String> configurations = ImportCandidates.load(
AutoConfiguration.class, getBeanClassLoader()).getCandidates();
Assert.notEmpty(configurations,
"No auto configuration classes found in "
+ "META-INF/spring/org.springframework.boot.autoconfigure."
+ "AutoConfiguration.imports");
return configurations;
}2.2 ImportCandidates.load() 内部实现
// ImportCandidates.java
public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
ClassLoader cl = classLoader != null ? classLoader
: ClassUtils.getDefaultClassLoader();
// 构造文件路径: META-INF/spring/{annotation.getName()}.imports
String location = String.format(LOCATION, annotation.getName());
// annotation.getName() = "org.springframework.boot.autoconfigure.AutoConfiguration"
// location = "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports"
return new ImportCandidates(cl.getResources(location));
}2.3 文件格式
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
# 每行一个全限定类名,支持 # 注释
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
...2.4 多 jar 同名文件合并
// ImportCandidates.java 构造器
private ImportCandidates(Enumeration<URL> urls) throws IOException {
List<String> candidates = new ArrayList<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
// 逐行读取,所有 jar 中的文件内容累加到同一 List
reader.lines()
.map(String::trim)
.filter(line -> !line.isEmpty() && !line.startsWith("#"))
.forEach(candidates::add);
}
}
this.candidates = Collections.unmodifiableList(candidates);
}多个 jar 包中同名 AutoConfiguration.imports 文件的内容按 URL 遍历顺序合并。
3. ConfigurationClassFilter 创建 4 个过滤器
3.1 源码
// ConfigurationClassFilter.java
class ConfigurationClassFilter {
private final List<ConditionFilter> filters;
ConfigurationClassFilter(ClassLoader classLoader, List<String> autoConfigurationClasses) {
// 创建 4 个内置过滤器
List<ConditionFilter> filters = new ArrayList<>();
filters.add(new OnClassConditionFilter()); // @ConditionalOnClass
filters.add(new OnBeanConditionFilter()); // @ConditionalOnBean / @ConditionalOnMissingBean
filters.add(new OnWebApplicationConditionFilter()); // @ConditionalOnWebApplication
filters.add(new OnPropertyConditionFilter()); // @ConditionalOnProperty
this.filters = Collections.unmodifiableList(filters);
}
}3.2 四个过滤器的职责
| 过滤器 | 匹配条件注解 | 过滤阶段 |
|---|---|---|
OnClassConditionFilter | @ConditionalOnClass / @ConditionalOnMissingClass | 第一阶段——最快速、消耗最低 |
OnBeanConditionFilter | @ConditionalOnBean / @ConditionalOnMissingBean / @ConditionalOnSingleCandidate | 第二阶段——需要 BeanFactory 元数据 |
OnWebApplicationConditionFilter | @ConditionalOnWebApplication / @ConditionalOnNotWebApplication | 第三阶段——检查 WebApplicationType |
OnPropertyConditionFilter | @ConditionalOnProperty | 第四阶段——检查 Environment 属性 |
3.3 过滤器的顺序对性能的影响
四阶段顺序的设计理由:先过滤开销最小的条件
OnClassCondition:只需要检查 ClassLoader 中是否存在指定类(Class.forName()),不涉及 BeanFactory 或 Environment,速度最快OnBeanCondition:需要查询 BeanDefinitionRegistry,相对较慢OnWebApplicationCondition:只需检查 WebApplicationType 枚举OnPropertyCondition:需要读取 Environment 属性源,相对较慢
以 DataSourceAutoConfiguration 为例:如果 DataSource.class 不在 classpath 上,OnClassCondition 阶段就过滤掉了,无需后续检查。
4. @AutoConfiguration(before=..., after=...) 排序
4.1 排序入口
// AutoConfigurationGroup.java
public void process(List<AutoConfigurationClass> autoConfigurationClasses) {
// 收集排序信息
for (AutoConfigurationClass autoConfigurationClass : autoConfigurationClasses) {
this.autoConfigurationClasses.add(autoConfigurationClass);
}
}
public Iterable<AutoConfigurationEntry> selectImports() {
if (this.autoConfigurationClasses.isEmpty()) {
return Collections.emptyList();
}
// 排序
List<AutoConfigurationClass> sortedClasses = AutoConfigurationSorter
.getInPriorityOrder(this.autoConfigurationClasses);
// 转换为 AutoConfigurationEntry
// ...
}4.2 AutoConfigurationSorter.getInPriorityOrder() 拓扑排序
// AutoConfigurationSorter.java
List<AutoConfigurationClass> getInPriorityOrder(
Collection<AutoConfigurationClass> classes) {
List<AutoConfigurationClass> sorted = new ArrayList<>();
Set<AutoConfigurationClass> visited = new HashSet<>();
// 对每个配置类执行 DFS 拓扑排序
for (AutoConfigurationClass clazz : classes) {
if (!visited.contains(clazz)) {
sort(clazz, classes, visited, sorted);
}
}
return sorted;
}
private void sort(AutoConfigurationClass clazz,
Collection<AutoConfigurationClass> classes,
Set<AutoConfigurationClass> visited,
List<AutoConfigurationClass> sorted) {
visited.add(clazz);
// 1. 处理 after 依赖 —— 先处理 shouldComeAfter 的类
for (AutoConfigurationClass after : clazz.getAfter()) {
if (!visited.contains(after) && classes.contains(after)) {
sort(after, classes, visited, sorted);
}
}
// 2. 处理 before 依赖 —— 寻找 shouldComeBefore 的类
for (AutoConfigurationClass before : clazz.getBefore()) {
if (!visited.contains(before) && classes.contains(before)) {
sort(before, classes, visited, sorted);
}
}
// 3. 将当前类加入排序结果
sorted.add(clazz);
}4.3 @AutoConfigureAfter / @AutoConfigureBefore / @AutoConfigureOrder 的解析
// @AutoConfiguration 注解中的排序属性
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@AutoConfigureBefore // 可选
@AutoConfigureAfter // 可选
@AutoConfigureOrder // 可选
public @interface AutoConfiguration {
@AliasFor(annotation = AutoConfigureBefore.class, attribute = "value")
Class<?>[] before() default {};
@AliasFor(annotation = AutoConfigureAfter.class, attribute = "value")
Class<?>[] after() default {};
}4.4 排序示例
@AutoConfiguration(after = DataSourceAutoConfiguration.class,
before = JdbcTemplateAutoConfiguration.class)
@ConditionalOnClass(DataSource.class)
public class HibernateJpaAutoConfiguration {
// ...
}
// 排序结果: DataSourceAutoConfiguration → HibernateJpaAutoConfiguration → JdbcTemplateAutoConfiguration4.5 拓扑排序优先级规则
| 排序方式 | 示例 | 优先级 |
|---|---|---|
@AutoConfigureBefore(XXX.class) | 当前类应在 XXX 之前 | 最高 |
@AutoConfigureAfter(XXX.class) | 当前类应在 XXX 之后 | 次高 |
@AutoConfigureOrder(N) | 数字越小优先级越高(类似 @Order) | 最低 |
5. AutoConfigurationImportSelector 排除机制
5.1 排除来源
// AutoConfigurationImportSelector.java
protected Set<String> getExclusions(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<>();
// 来源 1: @SpringBootApplication(exclude=...)
String[] exclude = attributes.getStringArray("exclude");
if (!ObjectUtils.isEmpty(exclude)) {
excluded.addAll(Arrays.asList(exclude));
}
// 来源 2: @SpringBootApplication(excludeName=...)
String[] excludeName = attributes.getStringArray("excludeName");
if (!ObjectUtils.isEmpty(excludeName)) {
excluded.addAll(Arrays.asList(excludeName));
}
// 来源 3: spring.autoconfigure.exclude 属性
List<String> propertyExcludes = getAutoConfigurationExclude();
if (propertyExcludes != null) {
excluded.addAll(propertyExcludes);
}
return excluded;
}5.2 getAutoConfigurationExclude() 从属性读取
// AutoConfigurationImportSelector.java
protected List<String> getAutoConfigurationExclude() {
if (this.beanFactory == null) {
return Collections.emptyList();
}
// 从 BeanFactory 的 Environment 中读取
String exclude = this.beanFactory.getEnvironment()
.getProperty("spring.autoconfigure.exclude");
if (exclude == null) {
return Collections.emptyList();
}
return Arrays.asList(StringUtils.trimArrayElements(
StringUtils.commaDelimitedListToStringArray(exclude)));
}5.3 三种排除方式的优先级
# 方式 1: @SpringBootApplication 注解属性
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)# 方式 2: application.yml 属性
spring:
autoconfigure:
exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration# 方式 3: 编程式
SpringApplication app = new SpringApplication(MyApp.class);
app.setExclude(DataSourceAutoConfiguration.class);三种方式最终合并为一个 Set<String>,无优先级之分——只要任意一种方式配置了排除,该配置类就会被排除。
5.4 排除后的日志输出
// AutoConfigurationImportSelector.java
protected AutoConfigurationEntry getAutoConfigurationEntry(
AnnotationMetadata annotationMetadata) {
// ...
Set<String> exclusions = getExclusions(metadata, attributes);
configurations.removeAll(exclusions);
// 记录排除日志
if (!exclusions.isEmpty()) {
logger.debug("Excluded auto configuration classes: {}", exclusions);
}
// ...
}启动时开启 debug 日志可看到排除的配置类:
logging:
level:
org.springframework.boot.autoconfigure: DEBUG6. 配置类去重逻辑
6.1 去重实现
// AutoConfigurationImportSelector.java
protected final <T> List<T> removeDuplicates(List<T> list) {
// 使用 LinkedHashSet 去重,同时保留顺序
return new ArrayList<>(new LinkedHashSet<>(list));
}6.2 为什么需要去重
多个 jar 包中的 AutoConfiguration.imports 文件可能包含相同的自动配置类:
# jar A 的 AutoConfiguration.imports
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
# jar B 的 AutoConfiguration.imports(同名文件合并后)
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration合并后列表:[AopAutoConfiguration, WebMvcAutoConfiguration, AopAutoConfiguration, RedisAutoConfiguration]
去重后:[AopAutoConfiguration, WebMvcAutoConfiguration, RedisAutoConfiguration]
6.3 LinkedHashSet 的特性
| 特性 | 效果 |
|---|---|
| 去重 | equals() / hashCode() 基于全限定类名字符串 |
| 保持顺序 | 保留第一次出现的顺序 |
| 线程安全 | 否(但此方法在单线程的启动阶段调用) |
7. ConfigurationClassFilter.match() 批量过滤
7.1 批量过滤流程
// ConfigurationClassFilter.java
List<String> match(List<String> classNames) {
// 1. 将所有配置类名解析为 AutoConfigurationClass
List<AutoConfigurationClass> autoConfigurationClasses = classNames.stream()
.map(this::resolveClassName)
.collect(Collectors.toList());
List<AutoConfigurationClass> matched = new ArrayList<>();
// 2. 对每个配置类执行四阶段过滤
for (AutoConfigurationClass autoConfigClass : autoConfigurationClasses) {
// 每个阶段都返回 ConditionOutcome
ConditionOutcome outcome = match(autoConfigClass);
if (outcome.isMatch()) {
matched.add(autoConfigClass);
} else {
// 记录过滤原因
if (logger.isTraceEnabled()) {
logger.trace("Skipped auto configuration class '{}': {}",
autoConfigClass.getClassName(), outcome.getMessage());
}
}
}
// 3. 返回匹配的类名列表
return matched.stream()
.map(AutoConfigurationClass::getClassName)
.collect(Collectors.toList());
}
private ConditionOutcome match(AutoConfigurationClass autoConfigClass) {
// 逐阶段过滤
for (ConditionFilter filter : this.filters) {
ConditionOutcome outcome = filter.match(autoConfigClass);
if (!outcome.isMatch()) {
return outcome; // 任一阶段不满足则跳过
}
}
return ConditionOutcome.match();
}7.2 四阶段短路过滤
AutoConfigurationClass
│
├─ Filter 1: OnClassConditionFilter
│ └─ match? → 否 → return "类 XXX 不在 classpath 上"
│ └─ match? → 是 → 进入 Filter 2
│
├─ Filter 2: OnBeanConditionFilter
│ └─ match? → 否 → return "Bean XXX 不存在"
│ └─ match? → 是 → 进入 Filter 3
│
├─ Filter 3: OnWebApplicationConditionFilter
│ └─ match? → 否 → return "WebApplicationType 不匹配"
│ └─ match? → 是 → 进入 Filter 4
│
└─ Filter 4: OnPropertyConditionFilter
└─ match? → 否 → return "属性 XXX 不满足"
└─ match? → 是 → return ConditionOutcome.match()7.3 ConditionMessage 日志记录
每个过滤结果都通过 ConditionMessage 结构化记录:
// ConditionOutcome.java
public class ConditionOutcome {
private final boolean match;
private final ConditionMessage message;
// match = false 时的典型消息:
// "OnClassCondition: required class 'org.springframework.jdbc.datasource.DataSource' not found"
// "OnBeanCondition: required bean 'dataSource' not found"
// "OnPropertyCondition: property 'spring.datasource.url' not set"
}这些消息最终出现在自动配置报告中:
// 通过 AutoConfigurationReportLoggingInitializer 输出
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
DataSourceAutoConfiguration - matched: @ConditionalOnClass found DataSource
Negative matches:
HibernateJpaAutoConfiguration - did not match: @ConditionalOnClass missing Hibernate8. AutoConfigurationImportEvent 发布
8.1 事件定义
// AutoConfigurationImportEvent.java
public class AutoConfigurationImportEvent extends ApplicationEvent {
private final List<String> candidateConfigurations;
private final Set<String> exclusions;
private final AutoConfigurationEntry autoConfigurationEntry;
public AutoConfigurationImportEvent(Object source,
List<String> candidateConfigurations, Set<String> exclusions,
AutoConfigurationEntry autoConfigurationEntry) {
super(source);
this.candidateConfigurations = candidateConfigurations;
this.exclusions = exclusions;
this.autoConfigurationEntry = autoConfigurationEntry;
}
}8.2 事件发布时机
// AutoConfigurationImportSelector.java
protected AutoConfigurationEntry getAutoConfigurationEntry(
AnnotationMetadata annotationMetadata) {
// ...
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
annotationMetadata, attributes);
// 发布 AutoConfigurationImportEvent
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(
this, configurations, exclusions, autoConfigurationEntry);
publishEvent(event);
return autoConfigurationEntry;
}8.3 AutoConfigurationImportListener 监听
// AutoConfigurationImportListener.java
@FunctionalInterface
public interface AutoConfigurationImportListener
extends ApplicationListener<AutoConfigurationImportEvent> {
@Override
void onAutoConfigurationImport(AutoConfigurationImportEvent event);
}8.4 内置监听器
Spring Boot 内置了 ConditionEvaluationReportAutoConfigurationImportListener,它记录自动配置的匹配结果,供条件评估报告使用:
// ConditionEvaluationReportAutoConfigurationImportListener.java
public class ConditionEvaluationReportAutoConfigurationImportListener
implements AutoConfigurationImportListener {
private final ConfigurableBeanFactory beanFactory;
@Override
public void onAutoConfigurationImport(AutoConfigurationImportEvent event) {
if (this.beanFactory != null) {
// 获取条件评估报告
ConditionEvaluationReport report = ConditionEvaluationReport
.get(this.beanFactory);
// 记录排除的配置类
report.recordExclusions(event.getExclusions());
// 记录评估的配置类
report.recordEvaluationCandidates(
event.getCandidateConfigurations());
}
}
}8.5 事件发布后的处理链
AutoConfigurationImportEvent
│
└─ ConditionEvaluationReportAutoConfigurationImportListener
└─ report.recordExclusions()
└─ report.recordEvaluationCandidates()
│
└─ 最终在 Actuator /conditions 端点展示
└─ GET /actuator/conditions
{
"contexts": {
"application": {
"positiveMatches": { ... },
"negativeMatches": { ... },
"exclusions": [ ... ]
}
}
}9. AutoConfigurationGroup 的分组逻辑
9.1 DeferredImportSelector 分组机制
AutoConfigurationImportSelector 实现了 DeferredImportSelector 接口,其分组在 DeferredImportSelector.Group 中进行:
// AutoConfigurationImportSelector.java
@Override
public Class<? extends DeferredImportSelector.Group> getImportGroup() {
return AutoConfigurationGroup.class;
}
// AutoConfigurationGroup.java(AutoConfigurationImportSelector 的内部类)
public class AutoConfigurationGroup
implements DeferredImportSelector.Group {
private final Map<String, AutoConfigurationClass> autoConfigurationClasses =
new LinkedHashMap<>();
@Override
public void process(AnnotationMetadata annotationMetadata,
DeferredImportSelector deferredImportSelector) {
// 收集经过过滤后的配置类
AutoConfigurationImportSelector selector =
(AutoConfigurationImportSelector) deferredImportSelector;
AutoConfigurationEntry entry = selector.getAutoConfigurationEntry(
annotationMetadata);
for (String configuration : entry.getConfigurations()) {
this.autoConfigurationClasses.put(configuration,
new AutoConfigurationClass(configuration, entry));
}
}
@Override
public Iterable<Entry> selectImports() {
if (this.autoConfigurationClasses.isEmpty()) {
return Collections.emptyList();
}
// 排序所有配置类
List<AutoConfigurationClass> sorted = AutoConfigurationSorter
.getInPriorityOrder(new ArrayList<>(this.autoConfigurationClasses.values()));
// 转换为 DeferredImportSelector.Entry
List<Entry> result = new ArrayList<>();
for (AutoConfigurationClass autoConfig : sorted) {
result.add(new Entry(autoConfig.getClassName(),
autoConfig.getAnnotationMetadata()));
}
return result;
}
}9.2 @AutoConfigureOrder 和 @Order 的区分
| 注解 | 作用范围 | 加载机制 |
|---|---|---|
@AutoConfigureOrder | 自动配置类之间的排序 | AutoConfigurationSorter.getInPriorityOrder() 拓扑排序 |
@AutoConfigureAfter | 自动配置类之间的先后依赖 | 拓扑排序的前置条件 |
@AutoConfigureBefore | 自动配置类之间的先后依赖 | 拓扑排序的后置条件 |
@Order / @Ordered | Bean 的排序(非自动配置类排序) | AnnotationAwareOrderComparator |
9.3 分组排序示例
@AutoConfiguration
@AutoConfigureOrder(1) // 高优先级
@AutoConfigureAfter(DataSourceAutoConfiguration.class) // 在 DataSource 之后
public class HibernateJpaAutoConfiguration { }
@AutoConfiguration
@AutoConfigureOrder(2)
@AutoConfigureAfter(HibernateJpaAutoConfiguration.class)
public class JdbcTemplateAutoConfiguration { }
@AutoConfiguration
@AutoConfigureOrder(3)
public class TransactionAutoConfiguration { }排序结果(拓扑序):
1. DataSourceAutoConfiguration (order=∞, 无前置依赖)
2. HibernateJpaAutoConfiguration (order=1, after=DataSource)
3. JdbcTemplateAutoConfiguration (order=2, after=HibernateJpa)
4. TransactionAutoConfiguration (order=3, 无前置依赖)10. skip() 方法跳过非配置类
10.1 源码
// ConfigurationClassParser.java
protected boolean skip(ConfigurationClass configurationClass) {
// 检查类上是否有 @Configuration 或等效注解
if (!isFullConfigurationClass(configurationClass)) {
return true; // 没有 @Configuration → 跳过
}
// 检查是否有 @Import、@ComponentScan 等注解
if (!hasImportOrComponentScan(configurationClass)) {
return true; // 没有 @Import 和 @ComponentScan → 跳过
}
return false;
}
private boolean isFullConfigurationClass(ConfigurationClass configClass) {
return configClass.getMetadata().isAnnotated(Configuration.class.getName())
|| configClass.getMetadata().isAnnotated(
"org.springframework.boot.autoconfigure.AutoConfiguration");
}
private boolean hasImportOrComponentScan(ConfigurationClass configClass) {
return configClass.getMetadata().isAnnotated(Import.class.getName())
|| configClass.getMetadata().isAnnotated(
ComponentScan.class.getName());
}10.2 判断标准
| 条件 | 是否跳过 | 示例 |
|---|---|---|
有 @Configuration + 有 @Import/@ComponentScan | ❌ 不跳过 | @Configuration @Import(...) public class MyConfig {} |
有 @Configuration + 无 @Import/@ComponentScan | ✅ 跳过 | 纯 @Bean 定义的配置类(由 ConfigurationClassParser 其他路径处理) |
无 @Configuration | ✅ 跳过 | 普通 POJO |
10.3 skip() 在自动配置中的角色
skip() 方法在 ConfigurationClassParser 处理配置类时调用,用于跳过无效的配置类定义。在自动配置场景中,自动配置类一定带有 @AutoConfiguration(等效于 @Configuration),因此 skip() 主要用于过滤已经被其他机制处理的配置类,避免重复注册。
总结
| 细节点 | 核心要点 |
|---|---|
① AutoConfiguration.imports 加载 | ImportCandidates.load(AutoConfiguration.class) 读取所有 jar 包中的同名文件并合并 |
② ConfigurationClassFilter 4 过滤器 | OnClassCondition(最快) → OnBeanCondition → OnWebApplicationCondition → OnPropertyCondition(最慢) |
| ③ 拓扑排序 | AutoConfigurationSorter.getInPriorityOrder() DFS 拓扑排序处理 before/after 依赖 |
| ④ 排除机制 | @EnableAutoConfiguration(exclude=/excludeName=) + spring.autoconfigure.exclude 三源合并 |
| ⑤ 去重逻辑 | LinkedHashSet 基于全限定类名去重,保留首次出现的顺序 |
| ⑥ 批量过滤 | 四阶段短路过滤,任一阶段不满足则跳过,ConditionMessage 记录原因 |
| ⑦ 事件发布 | AutoConfigurationImportEvent 由 ConditionEvaluationReportAutoConfigurationImportListener 记录到评估报告 |
| ⑧ 分组逻辑 | AutoConfigurationGroup.process() 收集 + selectImports() 排序输出 |
⑨ skip() 跳过 | 检查 @Configuration + @Import/@ComponentScan 避免重复注册 |