# SpringBoot 自动配置深度
用生活化的比喻,让你理解 SpringBoot 的启动流程、自动配置原理和 Starter 开发
前置知识:第04章 Spring 核心原理(IoC、Bean 生命周期、AOP)
阅读指南(初学者必看)
为什么你需要学习 SpringBoot 自动配置深度?
你每天都在用 SpringBoot,但出了问题往往不知道怎么排查。不理解自动配置,就无法:
- 理解 SpringBoot 启动时到底做了什么
- 理解 @ConditionalOnXxx 条件注解怎么控制 Bean 的创建
- 开发自定义 Starter 来封装游戏服务器的通用组件
学完本章,你能回答:
- SpringBoot 启动分几步?@EnableAutoConfiguration 什么时候生效?
- 自动配置类是怎么被发现的?怎么被条件过滤的?
- 如何开发一个自定义的 game-spring-boot-starter?
- spring.factories 和 AutoConfiguration.imports 有什么区别?
本文结构
第一部分:启动流程(SpringApplication.run 做了什么)
第二部分:自动配置原理(@EnableAutoConfiguration 全流程)
第三部分:自定义 Starter(开发 game-spring-boot-starter)
一、启动流程
生活类比:SpringBoot 启动就像开一家餐厅——先注册公司、装修、招人、采购食材、开业。
// SpringBoot 启动流程
1. new SpringApplication()
- 推断应用类型(Servlet / Reactive / None)
- 加载 ApplicationContextInitializer
- 加载 ApplicationListener
2. run()
- 创建 ApplicationContext
- 准备环境(Environment)
- 刷新上下文(@EnableAutoConfiguration 生效)
- 执行自动配置
- 启动完成
启动流程详细拆解
SpringApplication.run()
│
├── 1. 创建 SpringApplication
│ ├── 推断 Web 应用类型
│ ├── 加载 ApplicationContextInitializer(从 spring.factories)
│ └── 加载 ApplicationListener(从 spring.factories)
│
├── 2. 准备 Environment
│ ├── 创建 Environment
│ ├── 加载配置文件(application.yml / application.properties)
│ └── 处理 @PropertySource
│
├── 3. 创建 ApplicationContext
│ ├── Servlet → AnnotationConfigServletWebServerApplicationContext
│ └── Reactive → AnnotationConfigReactiveWebServerApplicationContext
│
├── 4. 准备上下文
│ ├── 设置 Environment
│ ├── 执行 ApplicationContextInitializer
│ └── 注册启动参数 Bean
│
├── 5. 刷新上下文 ⭐ 核心
│ ├── 执行 Spring 的 refresh()(见第04章)
│ └── @EnableAutoConfiguration 在这里生效
│
├── 6. 后处理
│ ├── 执行所有 Runner(CommandLineRunner / ApplicationRunner)
│ └── 发布 ApplicationReadyEvent
│
└── 7. 启动完成!
二、自动配置原理
// @EnableAutoConfiguration 核心流程
1. 扫描 META-INF/spring.factories(Spring Boot 2.x)
或 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(3.x)
2. 加载所有 AutoConfiguration 类
3. 根据 @ConditionalOnXxx 条件注解过滤
4. 满足条件的配置类生效
@EnableAutoConfiguration 详解
生活类比:自动配置就像自动售货机——你投币(引入依赖),它自动出货(配置 Bean)。
@SpringBootApplication =
@SpringBootConfiguration // 本质是 @Configuration
+ @EnableAutoConfiguration // 自动配置的核心
+ @ComponentScan // 组件扫描
@EnableAutoConfiguration 执行流程:
1. @Import(AutoConfigurationImportSelector.class)
│
2. AutoConfigurationImportSelector.selectImports()
│
3. 从 spring.factories 读取所有 AutoConfiguration 类
│
4. 过滤:去掉 @Conditional 条件不满足的
│
5. 排序:按 @AutoConfigureOrder 排序
│
6. 排除:去掉 @SpringBootApplication.exclude 指定的
│
7. 返回最终的配置类列表
│
8. Spring 容器加载这些配置类,注册 Bean
条件注解大全
| 注解 | 条件 | 生活类比 | 游戏场景 |
|---|---|---|---|
| @ConditionalOnClass | classpath 中有指定类 | 厨房有烤箱才能做蛋糕 | 引入 Netty 依赖才配置 Netty |
| @ConditionalOnMissingBean | 容器中没有指定 Bean | 你自己带了碗就不给你发 | 用户自定义 Bean 优先 |
| @ConditionalOnProperty | 配置文件中有指定属性 | 菜单上写了才有这道菜 | game.server.enabled=true |
| @ConditionalOnWebApplication | 是 Web 应用 | 是餐厅才能点菜 | 游戏网关是 Web 应用 |
| @ConditionalOnExpression | SpEL 表达式为 true | 满足条件才上菜 | 动态条件 |
自动配置的"约定大于配置"
SpringBoot 约定:
1. 引入 spring-boot-starter-web → 自动配置 Tomcat + SpringMVC
2. 引入 spring-boot-starter-data-redis → 自动配置 Redis 连接
3. 引入 mybatis-spring-boot-starter → 自动配置 SqlSessionFactory
4. application.yml 中的配置会覆盖默认值
这就是"约定大于配置"——你只需要引入依赖,SpringBoot 自动帮你配置好
三、自定义 Starter
// 自定义 Starter 的命名规范
// 官方:spring-boot-starter-xxx
// 第三方:xxx-spring-boot-starter
// 我们的示例:game-spring-boot-starter
game-spring-boot-starter/
├── pom.xml
├── src/main/java/
│ └── com/game/autoconfigure/
│ ├── GameAutoConfiguration.java // 自动配置类
│ ├── GameProperties.java // 配置属性
│ └── GameService.java // 核心服务
└── src/main/resources/
└── META-INF/
└── spring.factories // 注册自动配置
GameProperties.java
@ConfigurationProperties(prefix = "game.server")
public class GameProperties {
private boolean enabled = true;
private int maxRooms = 100;
private int maxPlayersPerRoom = 10;
private int tickRate = 20; // 每秒逻辑帧数
// getters and setters
}
GameAutoConfiguration.java
@AutoConfiguration
@ConditionalOnClass(GameService.class)
@ConditionalOnProperty(prefix = "game.server", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(GameProperties.class)
public class GameAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public GameService gameService(GameProperties properties) {
return new GameService(
properties.getMaxRooms(),
properties.getMaxPlayersPerRoom(),
properties.getTickRate()
);
}
}
spring.factories
# Spring Boot 2.x
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.game.autoconfigure.GameAutoConfiguration
AutoConfiguration.imports(Spring Boot 3.x)
# Spring Boot 3.x
# 文件路径:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.game.autoconfigure.GameAutoConfiguration
使用 Starter
# application.yml
game:
server:
enabled: true
max-rooms: 200
max-players-per-room: 8
tick-rate: 30
@Service
public class BattleService {
@Autowired
private GameService gameService; // 自动注入!
}
自问自答
Q:spring.factories 和 AutoConfiguration.imports 有什么区别? A:spring.factories 是 Spring Boot 2.x 的方式,一个文件注册所有类型的 SPI。AutoConfiguration.imports 是 Spring Boot 3.x 的新方式,专门用于自动配置,文件路径不同,更清晰。Spring Boot 3.x 两者都支持,但推荐新方式。
Q:自动配置的 Bean 和我手动定义的 Bean 冲突了怎么办? A:手动定义的 Bean 优先。自动配置类通常用 @ConditionalOnMissingBean,当容器中已有同名 Bean 时,自动配置不会创建。这就是 SpringBoot 的"用户定义优先"原则。
Q:为什么 Starter 要用 @ConditionalOnMissingBean? A:给用户留出覆盖默认配置的能力。用户可能需要自定义实现(如自定义的 GameService),@ConditionalOnMissingBean 保证用户的 Bean 不会被自动配置覆盖。
Q:如何排查自动配置是否生效?
A:1)启动时加 --debug,打印自动配置报告;2)在 application.yml 中设置 debug: true;3)用 Actuator 的 /conditions 端点查看。
实践任务
- 任务1:用
--debug启动 SpringBoot 应用,查看自动配置报告(哪些生效,哪些不生效) - 任务2:开发一个简单的 game-spring-boot-starter,包含自动配置类和属性类
- 任务3:在 Starter 中使用 @ConditionalOnProperty 控制功能开关
- 任务4:同时提供 spring.factories 和 AutoConfiguration.imports 两种注册方式
- 任务5:写一个自定义的 ApplicationContextInitializer,在容器刷新前打印环境信息
与其他章节的关联
| 本章内容 | 关联章节 | 关联点 |
|---|---|---|
| 启动流程 | 第04章 Spring 核心原理 | SpringBoot 启动 = Spring refresh + 自动配置 |
| 自动配置 | 第11章 游戏服务器架构 | 游戏组件用 Starter 封装 |
| 条件注解 | 第07章 字节码与动态编程 | 条件判断依赖类加载和反射 |
| Bean 注册 | 第04章 Spring 核心原理 | BeanDefinition 注册流程 |
| 配置属性 | 第15章 云原生与容器化 | 配置外部化是云原生的核心 |
上一章:04-Spring核心原理 | 下一章:06-数据库深度进阶