Spring Boot 深入原理
Spring Boot 的核心价值:约定大于配置,让你用最少的配置跑起来。理解自动配置原理,才能在出问题时有方向排查,才能自定义 Starter。
1. 自动配置原理
1.1 @SpringBootApplication 的三合一
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration // 标注这是一个配置类
@EnableAutoConfiguration // 开启自动配置
@ComponentScan // 组件扫描(扫当前包及子包)
public @interface SpringBootApplication {}
核心是 @EnableAutoConfiguration。
1.2 @EnableAutoConfiguration 做了什么
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AutoConfigurationImportSelector.class) // 关键:导入自动配置选择器
public @interface EnableAutoConfiguration {}
AutoConfigurationImportSelector 的工作:
Spring Boot 启动
↓
加载 spring-boot-autoconfigure.jar
↓
扫描 META-INF/spring.factories
↓
读取 EnableAutoConfiguration 对应的配置类列表
↓
过滤掉不满足 @Conditional 条件的配置类
↓
剩余的配置类 → 当作 @Configuration 加载到容器
1.3 spring.factories 文件
spring-boot-autoconfigure-*.jar 中的 META-INF/spring.factories:
# 自动配置类列表
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfigure.HelloAutoConfiguration,\
com.example.autoconfigure.DataSourceAutoConfiguration,\
...
Spring Boot 2.7+ 改为 META-INF/spring/org.springframework.boot.autoconfigure.EnableAutoConfiguration(SPI 文件)。
1.4 @Conditional 过滤条件
配置类注册之前,Spring 会检查条件:
@Configuration
@ConditionalOnClass(DataSource.class) // 类路径有 DataSource 才加载
@ConditionalOnProperty(prefix = "app", name = "enabled", havingValue = "true") // 配置开启
@ConditionalOnMissingBean(DataSource.class) // 容器里没有 DataSource 才加载
public class DataSourceAutoConfiguration {
@Bean
public DataSource dataSource() {
return new DruidDataSource();
}
}
常见的 @Conditional 注解:
| 注解 | 条件 |
|---|---|
@ConditionalOnClass |
类路径存在某类 |
@ConditionalOnMissingClass |
类路径不存在某类 |
@ConditionalOnProperty |
配置属性满足条件 |
@ConditionalOnBean |
容器中存在某 Bean |
@ConditionalOnMissingBean |
容器中不存在某 Bean |
@ConditionalOnWebApplication |
是 Web 应用 |
2. Spring Boot Starter 机制
2.1 Starter 的标准结构
my-starter/
├── src/main/java/com/example/mystarter/
│ ├── MyAutoConfiguration.java # 自动配置类
│ └── MyProperties.java # 配置属性类
└── src/main/resources/META-INF/
└── spring/org.springframework.boot.autoconfigure.EnableAutoConfiguration
└── com.example.mystarter.MyAutoConfiguration
2.2 自动配置类的写法
// 1. 配置属性类:绑定配置前缀
@ConfigurationProperties(prefix = "app.my-starter")
public class MyProperties {
private String name = "default"; // 默认值
private int timeout = 3000;
// 2. 自动配置类:根据条件注册 Bean
@Configuration
@EnableConfigurationProperties(MyProperties.class) // 开启属性绑定
@ConditionalOnClass(MyService.class) // 依赖的类存在才加载
@ConditionalOnProperty(prefix = "app.my-starter", name = "enabled", havingValue = "true", matchIfMissing = true)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 没有这个 Bean 才注册
public MyService myService(MyProperties props) {
return new MyService(props.getName(), props.getTimeout());
}
}
2.3 用户如何使用 Starter
# 用户只需在 application.yml 中配置
app:
my-starter:
enabled: true
name: custom-name
timeout: 5000
零 Java 代码,配置即生效。
3. SpringApplication 启动流程
3.1 启动流程图
SpringApplication.run()
↓
创建 SpringApplication 对象
↓
1. 推断 Web 应用类型(reactive / servlet / none)
2. 加载 spring.factories 的 ApplicationContextInitializer
3. 加载 spring.factories 的 ApplicationListener
4. 推断主启动类(从堆栈确定 main 所在的类)
↓
run(args)
↓
创建 BootstrapContext(引导上下文)
↓
配置 Headless 属性
↓
获取并运行 SpringApplicationRunListener( Starting 事件)
↓
创建并配置 Environment
↓
打印 Banner(启动图案)
↓
创建 ApplicationContext
↓
准备 Context:
1. 设置 Environment
2. 加载 source(主配置类)
3. 执行 initializer
4. 加载 Bean 定义(@Configuration 注解的类)
↓
刷新 Context:
1. 刷新容器(加载所有 Bean)
2. 执行 BeanFactoryPostProcessor
3. 自动配置(@EnableAutoConfiguration)
4. 注册 Listener(ApplicationListener)
↓
执行 Runner:
ApplicationRunner + CommandLineRunner
↓
发布 ApplicationReadyEvent 事件
↓
返回 ApplicationContext
3.2 SpringApplicationRunListener
生命周期的各个节点会触发对应事件:
| 阶段 | 方法 | 触发时机 |
|---|---|---|
| Starting | starting() |
应用刚启动 |
| Environment | environmentPrepared() |
Environment 准备完成 |
| Context | contextPrepared() |
Context 创建完成 |
| Loaded | contextLoaded() |
Context 加载完成 |
| Started | started() |
Context 启动完成 |
| Ready | ready() |
应用就绪 |
自定义 RunListener 可用于:
- 启动流程日志
- 自定义健康检查
- 初始化任务
4. Spring Boot 内嵌服务器
4.1 自动选择机制
Spring Boot 2.x 根据类路径判断:
Tomcat 类存在 → Tomcat(默认)
↓ 不存在
Jetty 类存在 → Jetty
↓ 不存在
Undertow 类存在 → Undertow
↓ 不存在
非 Web 应用
排除默认 Tomcat:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
4.2 常用配置
server:
port: 8080
servlet:
context-path: /api
tomcat:
threads:
max: 200 # 最大线程数
min-spare: 10 # 最小空闲线程
accept-count: 100 # 满后最大等待队列
max-connections: 10000 # 最大连接数
5. Spring Boot Actuator 监控
5.1 引入 Actuator
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
5.2 常用端点
| 端点 | 说明 | 访问 |
|---|---|---|
/actuator/health |
健康检查 | {"status": "UP"} |
/actuator/info |
应用信息 | 自定义 |
/actuator/metrics |
指标数据 | CPU、内存、JVM 等 |
/actuator/env |
环境变量 | 所有配置 |
/actuator/beans |
容器中所有 Bean | Bean 列表 |
/actuator/mappings |
所有 URL 映射 | REST API 列表 |
/actuator/trace |
最近 HTTP 请求 | 请求追踪 |
/actuator/heapdump |
堆Dump(需认证) | 下载 |
5.3 暴露端点配置
management:
endpoints:
web:
exposure:
include: health,info,metrics
exclude: env,beans
endpoint:
health:
show-details: when_authorized # 只给授权用户看详情
5.4 自定义健康检查
@Component
public class MyHealthIndicator implements HealthIndicator {
@Override
public Health health() {
boolean healthy = checkMyService();
if (healthy) {
return Health.up()
.withDetail("key", "value")
.build();
}
return Health.down()
.withDetail("error", "service unavailable")
.build();
}
}
6. Spring Boot 异常处理
6.1 错误处理流程
请求到达 DispatcherServlet
↓
HandlerExceptionResolver 处理异常
↓
默认异常处理:
@ExceptionHandler → Controller 内处理
@ControllerAdvice → 全局异常处理
DefaultHandlerExceptionResolver → Spring 标准异常
ErrorMvcAutoConfiguration → /error 页面
6.2 @ControllerAdvice 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public Result<?> handleBusiness(BusinessException e) {
return Result.error(e.getCode(), e.getMessage());
}
@ExceptionHandler(Exception.class)
public Result<?> handleOther(Exception e) {
return Result.error(500, "服务器内部错误");
}
}
6.3 自定义 ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(
WebRequest webRequest, ErrorAttributeOptions options) {
Map<String, Object> attrs = super.getErrorAttributes(webRequest, options);
attrs.put("custom", "custom-info"); // 添加自定义字段
return attrs;
}
}
7. 条件注册 Bean 的实际应用
7.1 多个数据源下的动态切换
@Configuration
public class DataSourceConfiguration {
@Bean
@Primary // 默认数据源
@ConditionalOnProperty(name = "db.primary", havingValue = "mysql")
public DataSource mysqlDataSource() { ... }
@Bean
@ConditionalOnProperty(name = "db.primary", havingValue = "postgres")
public DataSource postgresDataSource() { ... }
}
7.2 根据环境激活不同配置
@Configuration
@Profile("prod") // 只有 prod 环境才加载
public class ProdConfiguration {
@Bean
public DataSource prodDataSource() { ... }
}
8. 常用 Spring Boot 技巧
8.1 启动失败自动重启
spring-boot-devtools:代码修改后自动重启应用(不是热替换,是重启)。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
8.2 Banner 自定义
# 或者创建 src/main/resources/banner.txt
spring:
main:
banner-mode: console
8.3 多环境配置切换
src/main/resources/
├── application.yml # 默认配置
├── application-dev.yml # 开发环境
├── application-test.yml # 测试环境
└── application-prod.yml # 生产环境
# application.yml 中指定激活
spring:
profiles:
active: dev