Spring Boot 自动配置源码精读
概述
本文深入 Spring Boot 自动配置的核心实现,理解 @SpringBootApplication 如何自动激活数百个配置类、条件评估如何工作。
一、@SpringBootApplication 组合注解
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // 等价于 @Configuration
@EnableAutoConfiguration // 开启自动配置
@ComponentScan(excludeFilters = { // 组件扫描
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
// ...
}核心在于 @EnableAutoConfiguration:
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // 注册当前包名
@Import(AutoConfigurationImportSelector.class) // 核心:导入自动配置
public @interface EnableAutoConfiguration {
// ...
}二、AutoConfigurationImportSelector
2.1 selectImports() — 选择自动配置类
java
// AutoConfigurationImportSelector 实现了 DeferredImportSelector
// 在普通 @Configuration 类加载完成后才执行(保证 BeanFactoryPostProcessor 优先)
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 1. 检查 auto-configuration 是否启用
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 2. 加载 AutoConfiguration.imports 中的配置类
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
// 3. 返回最终会加载的配置类名数组
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}2.2 getAutoConfigurationEntry() — 获取自动配置条目
java
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 1. 检查是否启用
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 2. 获取注解属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 3. 从 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 获取候选配置
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 4. 去重
configurations = removeDuplicates(configurations);
// 5. 获取要排除的配置(@SpringBootApplication(exclude=...))
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 6. 条件评估过滤(核心!)
configurations = getConfigurationClassFilter().filter(configurations);
// 7. 触发 AutoConfigurationImportEvent
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}2.3 加载候选项
java
// 从 spring.factories(2.x)或 AutoConfiguration.imports(3.x)加载
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// Spring Boot 3.x:从 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 加载
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring/..." +
" If you are using a custom packaging, make sure file is correct.");
return configurations;
}配置文件示例(AutoConfiguration.imports):
properties
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
# Spring Boot 3.x 默认包含约 145 个自动配置类
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
# ... 更多配置三、条件评估过滤
3.1 ConfigurationClassFilter
java
// AutoConfigurationImportSelector 的内部类
// 负责根据 @Conditional 条件过滤配置类
private static class ConfigurationClassFilter {
private final List<Condition> filters;
ConfigurationClassFilter(ClassLoader classLoader, List<String> configurations) {
// 从所有配置类上提取 @Conditional 注解
// 建立索引:配置类 → 其上的所有条件
this.filters = buildFilters(classLoader, configurations);
}
List<String> filter(List<String> configurations) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean skipped = false;
// 逐一检查每个配置类
for (int i = 0; i < candidates.length; i++) {
String configurationClassName = candidates[i];
// 获取该配置类的所有条件
List<Condition> conditionClasses = this.filters.get(configurationClassName);
if (conditionClasses != null) {
// 评估所有条件
for (Condition condition : conditionClasses) {
// 核心:调用 Condition.matches()
if (!condition.match(this.conditionContext, this.metadataReaderFactory.getMetadataReader(configurationClassName))) {
// 条件不满足 → 跳过此配置类
candidates[i] = null;
skipped = true;
break;
}
}
}
}
// 移除跳过的配置
return skipped ? filterSkipped(candidates) : configurations;
}
}3.2 ConditionEvaluator.shouldSkip()
java
// ConditionEvaluator 是 Spring Framework 中的实际评估器
// @Conditional 注解的处理逻辑
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
// 1. 获取类上所有 @Conditional 注解
for (ConditionAnnotation conditionAnnotation : getConditionAnnotations(metadata)) {
// 2. 实例化 Condition 实现类
List<Condition> conditions = getConditions(conditionAnnotation);
for (Condition condition : conditions) {
// 3. 检查 Condition 的配置阶段(REGISTER_BEAN / PARSE_CONFIGURATION)
ConfigurationPhase requiredPhase = getRequiredPhase(condition);
if (requiredPhase != null && phase != requiredPhase) continue;
// 4. 调用 Condition.matches()(核心!)
if (!condition.matches(this.context, metadata)) {
return true; // 条件不满足 → 跳过
}
}
}
return false;
}四、核心条件注解实现
4.1 OnClassCondition
java
// @ConditionalOnClass 的实现
// 检查指定的 Class 是否存在于 classpath
@Order(Ordered.HIGHEST_PRECEDENCE)
class OnClassCondition extends FilteringSpringBootCondition {
@Override
protected ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
// 获取 @ConditionalOnClass 的值
ClassLoader classLoader = context.getClassLoader();
ConditionMessage matchMessage = ConditionMessage.empty();
// 获取注解属性
List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);
if (onClasses != null) {
// 检查每个类是否可加载
List<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);
if (!missing.isEmpty()) {
// 缺少类 → 不匹配
return ConditionOutcome.noMatch(
ConditionMessage.forCondition(ConditionalOnClass.class)
.didNotFind("required class", "required classes")
.items(Style.QUOTE, missing));
}
}
return ConditionOutcome.match(matchMessage);
}
}4.2 OnBeanCondition
java
// @ConditionalOnBean / @ConditionalOnMissingBean 的实现
// 检查 BeanFactory 中是否已存在指定 Bean
@Order(Ordered.LOWEST_PRECEDENCE) // 最后执行(等 Bean 都注册完了)
class OnBeanCondition extends FilteringSpringBootCondition {
@Override
protected ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
// 获取要检查的 Bean 信息(type、name、annotation)
BeanSearchSpec spec = new BeanSearchSpec(context, metadata, ConditionalOnBean.class);
// 从 BeanFactory 搜索 Beans
Set<String> matchingBeans = getBeanNamesForSearch(spec, context, metadata);
if (spec.isSearchStrategy(SearchStrategy.PARENTS)) {
// 搜索父容器
BeanFactory parent = context.getBeanFactory().getParentBeanFactory();
if (parent instanceof ListableBeanFactory) {
matchingBeans.addAll(getBeanNamesForSearch(spec, context, (ListableBeanFactory) parent));
}
}
if (ConditionalOnBean.class.isInstance(metadata.getAnnotation(ConditionalOnBean.class))) {
// @ConditionalOnBean:必须存在匹配的 Bean
return new ConditionOutcome(!matchingBeans.isEmpty(),
ConditionMessage.forCondition(ConditionalOnBean.class)
.found("bean", "beans")
.items(Style.QUOTE, matchingBeans));
} else {
// @ConditionalOnMissingBean:必须不存在匹配的 Bean
return new ConditionOutcome(matchingBeans.isEmpty(),
ConditionMessage.forCondition(ConditionalOnMissingBean.class)
.didNotFind("bean", "beans")
.items(Style.QUOTE, matchingBeans));
}
}
}4.3 OnPropertyCondition
java
// @ConditionalOnProperty 的实现
// 检查配置属性是否存在
@Order(Ordered.HIGHEST_PRECEDENCE + 40)
class OnPropertyCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
// 获取 @ConditionalOnProperty 注解属性
List<AnnotationAttributes> allAnnotationAttributes =
attributesFor(metadata, ConditionalOnProperty.class);
for (AnnotationAttributes annotationAttributes : allAnnotationAttributes) {
// 解析属性
String prefix = annotationAttributes.getString("prefix");
String havingValue = annotationAttributes.getString("havingValue");
String[] names = annotationAttributes.getStringArray("name");
boolean matchIfMissing = annotationAttributes.getBoolean("matchIfMissing");
// 从 Environment 获取属性值
for (String name : names) {
String key = prefix + "." + name;
String value = context.getEnvironment().getProperty(key);
if (value == null) {
if (!matchIfMissing) {
return ConditionOutcome.noMatch("property " + key + " not set");
}
} else if (!value.equals(havingValue) && !havingValue.isEmpty()) {
return ConditionOutcome.noMatch("property " + key + " = " + value);
}
}
}
return ConditionOutcome.match();
}
}五、自动配置报告
5.1 条件评估报告
java
// AutoConfigurationReport(自动配置报告)
// 通过 debug=true 或 trace=true 查看
// application.yml
debug: true
// 控制台输出:
// ============================
// AUTO-CONFIGURATION REPORT
// ============================
// Positive matches(匹配成功的自动配置):
// DataSourceAutoConfiguration matched:
// - @ConditionalOnClass found required class 'javax.sql.DataSource' (OnClassCondition)
// - @ConditionalOnProperty (spring.datasource.type) matched (OnPropertyCondition)
// Negative matches(未匹配的自动配置):
// ActiveMQAutoConfiguration:
// Did not match:
// - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
// Exclusions(排除的自动配置):
// None5.2 自定义条件
java
// 自定义条件:只有特定地区才加载
public class RegionCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String region = context.getEnvironment().getProperty("app.region");
return "cn".equals(region);
}
}
@Configuration
@Conditional(RegionCondition.class)
public class ChinaSpecificConfiguration {
// 只在中国区加载
}六、总结
| 知识点 | 关键源码 | 说明 |
|---|---|---|
| 自动配置入口 | @EnableAutoConfiguration → AutoConfigurationImportSelector | 导入自动配置类 |
| 配置加载 | SpringFactoriesLoader.loadFactoryNames() | 从 AutoConfiguration.imports 加载 |
| 条件过滤 | ConfigurationClassFilter.filter() | 根据 @Conditional 过滤 |
| OnClassCondition | ClassNameFilter.MISSING | 检查 classpath 是否存在类 |
| OnBeanCondition | BeanFactory.getBeanNamesForType() | 检查 BeanFactory 是否存在 Bean |
| OnPropertyCondition | Environment.getProperty() | 检查配置属性 |
| 配置报告 | AutoConfigurationReport | 记录所有条件的匹配结果 |
参考链接: