本文从
@SpringBootApplication出发,逐层深入剖析 Spring Boot 自动装配的触发机制、SPI 加载、条件过滤全流程,并给出自定义 Starter 的完整实现方案。
目录
| 章节 | 说明 |
|---|---|
| 整体架构 | 核心注解关系与组件职责 |
| 核心流程 | 从启动到 Bean 注册的完整链路 |
| 源码分析 | 关键类与方法逐行解读 |
| 条件注解 | @ConditionalOnXxx 全家桶 |
| 自定义 Starter | 编写可复用的自动装配模块 |
| 最佳实践 | 生产环境排查与调优建议 |
| 常见问题 | 典型故障与排查思路 |
整体架构
注解层级关系
graph TD
A["@SpringBootApplication"] --> B["@SpringBootConfiguration"]
A --> C["@ComponentScan"]
A --> D["@EnableAutoConfiguration"]
D --> E["@AutoConfigurationPackage"]
D --> F["@Import(AutoConfigurationImportSelector)"]
F --> G["AutoConfigurationImportSelector"]
G --> H["SpringFactoriesLoader<br/>(Boot < 2.7)"]
G --> I["ImportCandidates<br/>(Boot ≥ 2.7)"]
H --> J["META-INF/spring.factories"]
I --> K["META-INF/spring/<br/>AutoConfiguration.imports"]
style D fill:#cfc,stroke:#060
style G fill:#cfc,stroke:#060
核心组件职责
| 组件 | 所在包 | 职责 |
|---|---|---|
@EnableAutoConfiguration |
spring-boot-autoconfigure |
开关注解,触发自动装配 |
AutoConfigurationImportSelector |
spring-boot-autoconfigure |
SPI 加载 + 条件过滤的核心选择器 |
SpringFactoriesLoader |
spring-core |
读取 spring.factories 的工具类 |
ImportCandidates |
spring-boot |
Boot 2.7+ 读取 .imports 文件 |
@Conditional 系列 |
spring-context |
按条件决定 Bean 是否注册 |
核心流程
触发时机
自动装配的入口在 Spring 容器刷新阶段(AbstractApplicationContext#refresh),由 ConfigurationClassParser 解析 @Import 注解时触发 DeferredImportSelector。
sequenceDiagram
participant App as SpringApplication
participant Ctx as AnnotationConfigApplicationContext
participant Parser as ConfigurationClassParser
participant Selector as AutoConfigurationImportSelector
participant Loader as SpringFactoriesLoader
App->>Ctx: refresh()
Ctx->>Parser: parse(@SpringBootApplication)
Parser->>Parser: 解析 @EnableAutoConfiguration
Parser->>Selector: selectImports()
Selector->>Loader: loadFactoryNames() / loadAutoConfigurationClasses()
Loader-->>Selector: 候选配置类列表(100+个)
Selector->>Selector: 条件过滤(@ConditionalOnXxx)
Selector-->>Parser: 过滤后的配置类列表
Parser->>Ctx: 注册为 BeanDefinition
加载文件路径对比
| Boot 版本 | 配置文件 | 读取方式 |
|---|---|---|
| < 2.7 | META-INF/spring.factories |
SpringFactoriesLoader.loadFactoryNames() |
| ≥ 2.7 | META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports |
ImportCandidates.load() |
| 3.x | 同 2.7+,spring.factories 仍向后兼容但不推荐 |
ImportCandidates.load() |
为什么 2.7+ 改用 .imports 文件?
① 性能:避免解析大文件
spring.factories 是通用 SPI,启动时为了找 EnableAutoConfiguration 一个 key,却要解析整个文件——Spring Boot 官方的 spring.factories 混了 100+ 条目(ApplicationContextInitializer、EnvironmentPostProcessor 等各种用途)。新文件专职自动配置,无需扫描无关内容。
② 关注点分离
spring.factories 是"大杂烩",职责太多。将自动配置类单独提取到独立文件,语义清晰,也便于 IDE 和静态分析工具精确识别哪些是自动配置类。
③ AOT / GraalVM Native Image 支持
Spring Boot 3.x 的核心目标之一是支持编译期 AOT 和 GraalVM 原生镜像。spring.factories 依赖运行时反射加载,难以静态分析;.imports 文件格式在编译期可被处理,生成反射元数据,不需要运行时动态发现。
④ 配合 @AutoConfiguration 注解
新格式配合 Spring Boot 2.7+ 新增的 @AutoConfiguration(@Configuration + 禁止被 @ComponentScan 扫到的语义),明确区分"框架自动配置类"和"用户 @Configuration 类",避免混淆。
源码分析
关键类一览
| 类名 | 模块 | 职责 |
|---|---|---|
AutoConfigurationImportSelector |
autoconfigure | 实现 DeferredImportSelector,核心入口 |
AutoConfigurationMetadataLoader |
autoconfigure | 加载 spring-autoconfigure-metadata.properties,用于快速过滤 |
ConditionEvaluator |
spring-context | 执行 @Conditional 条件判断 |
OnClassCondition |
autoconfigure | @ConditionalOnClass 的实现 |
getAutoConfigurationEntry 核心方法
// AutoConfigurationImportSelector#getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 1. 从 spring.factories 或 .imports 文件加载全部候选类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 2. 去重
configurations = removeDuplicates(configurations);
// 3. 排除 exclude 指定的类
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 4. 通过 AutoConfigurationImportFilter 做轻量级条件过滤(不初始化 Bean)
configurations = getConfigurationClassFilter().filter(configurations);
// 5. 触发 AutoConfigurationImportEvent 事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
关键点:第 4 步的 filter 使用 spring-autoconfigure-metadata.properties 做快速预过滤(不加载类),避免大量反射,这是性能优化的核心手段。
getCandidateConfigurations 加载入口
// AutoConfigurationImportSelector#getCandidateConfigurations
protected List<String> getCandidateConfigurations(
AnnotationMetadata metadata, AnnotationAttributes attributes) {
// Boot 2.7+ 优先走 ImportCandidates
List<String> configurations = new ArrayList<>(
SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
.forEach(configurations::add);
return configurations;
}
spring.factories 文件格式(Boot < 2.7)
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
AutoConfiguration.imports 文件格式(Boot ≥ 2.7)
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
条件注解
条件注解是自动装配"按需生效"的核心机制,所有条件注解都基于 @Conditional + Condition 接口实现。
常用条件注解全览
| 注解 | 生效条件 | 典型用途 |
|---|---|---|
@ConditionalOnClass |
classpath 中存在指定类 | 依赖可选时 |
@ConditionalOnMissingClass |
classpath 中不存在指定类 | 互斥依赖 |
@ConditionalOnBean |
容器中已有指定 Bean | 依赖其他 Bean |
@ConditionalOnMissingBean |
容器中没有指定 Bean | 允许用户覆盖 |
@ConditionalOnProperty |
配置属性值匹配 | 开关控制 |
@ConditionalOnWebApplication |
是 Web 应用 | Web 专属配置 |
@ConditionalOnNotWebApplication |
非 Web 应用 | 非 Web 配置 |
@ConditionalOnResource |
classpath 中存在指定资源文件 | 配置文件存在 |
@ConditionalOnExpression |
SpEL 表达式为 true | 复杂条件 |
典型用法示例
@Configuration
// classpath 有 RedisConnectionFactory 才生效
@ConditionalOnClass(RedisConnectionFactory.class)
// 没有用户自定义的 RedisTemplate 时才注册默认实现
@ConditionalOnMissingBean(name = "redisTemplate")
// 配置项 spring.data.redis.enabled=true(默认 true)时生效
@ConditionalOnProperty(prefix = "spring.data.redis", name = "enabled",
matchIfMissing = true)
public class RedisAutoConfiguration {
@Bean
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
return template;
}
}
核心设计理念:
@ConditionalOnMissingBean是"用户优先"原则的实现——用户显式定义的 Bean 永远比自动装配的优先级高。
自定义 Starter
命名规范
| 类型 | 命名规范 | 示例 |
|---|---|---|
| 官方 Starter | spring-boot-starter-{name} |
spring-boot-starter-redis |
| 第三方 Starter | {name}-spring-boot-starter |
mybatis-spring-boot-starter |
推荐目录结构
my-spring-boot-starter/
├── src/main/java/
│ └── com/example/
│ ├── MyProperties.java ← 配置属性类
│ ├── MyService.java ← 核心服务
│ └── MyAutoConfiguration.java ← 自动装配类
└── src/main/resources/
└── META-INF/spring/
└── org.springframework.boot.autoconfigure.AutoConfiguration.imports
实现步骤
第一步:定义配置属性类
@ConfigurationProperties(prefix = "my.service")
public class MyProperties {
private boolean enabled = true;
private String endpoint = "http://localhost:8080";
// getter / setter
}
第二步:编写自动装配类
@AutoConfiguration // Boot 2.7+ 替代 @Configuration
@ConditionalOnClass(MyService.class)
@ConditionalOnProperty(prefix = "my.service",
name = "enabled", matchIfMissing = true)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyProperties props) {
return new MyService(props.getEndpoint());
}
}
第三步:注册自动装配类(Boot ≥ 2.7)
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.MyAutoConfiguration
第四步:声明 pom 依赖
<dependencies>
<!-- 提供 @ConfigurationProperties 等注解处理器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- 可选:生成 IDE 配置提示 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
最佳实践
调试自动装配
# 启动时打印自动装配报告(哪些生效、哪些被排除及原因)
java -jar app.jar --debug
# 或在 application.yaml 中配置
logging:
level:
org.springframework.boot.autoconfigure: DEBUG
排除不需要的自动装配
// 方式一:注解排除
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
RedisAutoConfiguration.class
})
// 方式二:配置文件排除(不改代码,推荐)
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
控制自动装配顺序
@AutoConfiguration
// 在 DataSourceAutoConfiguration 之后执行
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
// 在 CacheAutoConfiguration 之前执行
@AutoConfigureBefore(CacheAutoConfiguration.class)
public class MyAutoConfiguration { }
常见问题
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 自定义 Starter 的 Bean 未注册 | .imports 文件路径错误或未打包 |
检查 META-INF/spring/ 目录,用 jar tf 确认文件存在 |
| 自动装配类生效但配置未生效 | @EnableConfigurationProperties 漏写 |
在自动装配类上补加该注解 |
| 两个 Starter 的 Bean 冲突 | 缺少 @ConditionalOnMissingBean |
在默认 Bean 上加条件注解,让用户可覆盖 |
| Boot 3.x 升级后自动装配失效 | 仍用 spring.factories 旧格式 |
迁移到 AutoConfiguration.imports 文件 |
| 调试模式下看不到某配置类 | 该类在预过滤阶段就被排除 | 检查 spring-autoconfigure-metadata.properties 中对应条件 |
参考资料
- Spring Boot 官方文档 — Auto-configuration
- SpringBoot 启动流程源码分析(自动装配在
refresh()阶段触发,与启动流程深度关联)
评论 (0)
发表评论