Spring Boot 自动配置:从 2.x 到 3.x 的进化之路
一、前言:为什么“零配置”能跑起来?
大多数 Spring Boot 开发者第一次新建项目时都会惊叹:
“我只写了一个
@SpringBootApplication
,Tomcat、数据源、Redis 全都准备好了?”
这背后就是 自动配置(Auto-Configuration)。本文用 源码 + 图示 带你穿透原理,并对比 2.x 与 3.x 的关键差异。
二、自动配置全景图(一张图秒懂)
┌─────────────┐ ┌──────────────────────┐
│ @SpringBootApp│─────▶│@EnableAutoConfiguration│
└────┬────────┘ └────┬─────────────────┘│ ││ ┌─────────┴────────┐│ │AutoConfigurationImportSelector││ └────┬─────────────┘│ ││ ┌───────────┴──────────┐│ │读取候选配置类列表 ││ │(spring.factories 2.x) ││ │(.imports 3.x) ││ └───────────┬──────────┘│ ││ ┌───────────┴──────────┐│ │条件注解过滤 ││ │@ConditionalOnClass... ││ └───────────┬──────────┘│ │
┌────┴──────────────┴────────────┐
│ BeanDefinitionRegistry │
│ 注册生效的自动配置类 │
└────────────────────────────────┘
三、2.x 实现细节(spring.factories 时代)
1️⃣ 文件位置与格式
文件:META-INF/spring.factories
格式:键值对
# 2.x 示例
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
2️⃣ 源码入口
@EnableAutoConfiguration
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration { }
AutoConfigurationImportSelector#selectImports
会解析上述文件,返回 String[]
候选类。
3️⃣ 条件过滤示例(DataSourceAutoConfiguration)
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(DataSource.class)
public class DataSourceAutoConfiguration {// 注册 DataSource Bean
}
@ConditionalOnClass
:类路径存在指定类才生效@ConditionalOnMissingBean
:用户没写自己的 DataSource 才生效
四、3.x 实现细节(.imports 文件时代)
1️⃣ 文件位置与格式
文件:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
格式:一行一个类名
# 3.x 示例
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
2️⃣ 源码差异
AutoConfigurationImportSelector
在 3.x 中改为读取 .imports
文件,不再解析键值对:
// 伪代码
List<String> configurations = loadAutoConfigurationImports();
return configurations.toArray(new String[0]);
3️⃣ 好处
- 启动更快:无需解析键值对
- 文件更小:纯文本列表
- 冲突更少:一个文件只放自动配置类
五、2.x vs 3.x 对比表
维度 | 2.x | 3.x |
---|---|---|
配置文件 | spring.factories | AutoConfiguration.imports |
格式 | key=value | 一行一类名 |
加载效率 | 需 split & trim | 直接读取 |
冲突解决 | 多 key 冲突需合并 | 无 key,天然无冲突 |
条件注解 | 完全一致 | 完全一致 |
用户自定义 Bean | 仍然优先(@ConditionalOnMissingBean) | 仍然优先 |
六、实战:如何自定义 Starter(兼容 2.x & 3.x)
1️⃣ 2.x 写法
src/main/resources/META-INF/spring.factoriesorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xxx.MyStarterAutoConfiguration
2️⃣ 3.x 写法
src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importscom.xxx.MyStarterAutoConfiguration
3️⃣ 条件示例
@Configuration
@ConditionalOnClass(MyService.class)
@ConditionalOnMissingBean(MyService.class)
public class MyStarterAutoConfiguration {@Beanpublic MyService myService() {return new MyService();}
}
七、面试 30 秒答案
“Spring Boot 自动配置核心是 AutoConfigurationImportSelector 读取候选类列表,2.x 用
spring.factories
键值对,3.x 用AutoConfiguration.imports
一行一类名,条件注解过滤后注册 Bean。3.x 启动更快、无键冲突。”
八、总结
- 原理不变:条件注解 + 用户 Bean 优先
- 文件变:2.x 键值对 → 3.x 纯列表
- 性能升:3.x 启动更快、冲突更少