后端框架(02):Spring Boot——启动原理、自动装配、WebFlux 响应式、调优
更新时间:2026-09-01。本文是
backend/framework/后端框架第 02 篇,接 Node.js 与 NestJS。Spring Boot 是 Java 生态最流行的后端框架,约定大于配置,自动装配简化了大量配置。理解启动原理和自动装配,才能快速定位依赖问题和性能问题。
本文要回答的问题
- Spring Boot 启动过程是什么?自动装配怎么工作?
- @SpringBootApplication 背后做了什么?
- Spring MVC 和 WebFlux 有什么区别?什么时候用 WebFlux?
- Spring Boot 性能调优怎么做?内存优化、启动加速?
一、@SpringBootApplication
java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}@SpringBootApplication 是三个注解的组合:
@Configuration—— 配置类@EnableAutoConfiguration—— 开启自动装配@ComponentScan—— 组件扫描,扫描当前包及其子包
二、自动装配原理
1. 启动 SpringApplication → SpringFactoriesLoader 加载
2. 从 META-INF/spring.factories 读取所有 AutoConfiguration
3. 根据 @Conditional 条件(类存在性、属性配置)过滤
4. 满足条件的自动装配类注册到 Spring 容器
// 例子:DataSourceAutoConfiguration
@ConditionalOnClass(DataSource.class) // 类路径有 DataSource 才装配
@ConditionalOnProperty(prefix = "spring.datasource") // 配置存在才装配
public class DataSourceAutoConfiguration {
// 自动注册 DataSource bean
}经验:
- 引入 starter → 自动装配,不需要手动配置
- starter 只是 pom 文件,只做依赖管理,不做实现
- 自动装配真正工作是在 spring.factories 中
三、启动过程
SpringApplication.run 步骤:
1. 创建 SpringApplication 实例
- 推断应用类型(Servlet 还是 Reactive)
- 查找 ApplicationContextInitializer
- 查找 ApplicationListeners
2. 调用 run 方法
- 记录启动时间
- 启动 Spring 容器前的准备
- 创建 Environment(配置环境)
- 创建 ApplicationContext(容器上下文)
- 加载 bean definitions
- refresh context(初始化所有单例 bean)
- 调用 runner(CommandLineRunner、ApplicationRunner)
- 发布 ContextRefreshedEvent
3. 启动完成四、Spring MVC vs WebFlux
| 对比 | Spring MVC | Spring WebFlux |
|---|---|---|
| 并发模型 | Servlet 线程池 | 响应式,事件循环 |
| 阻塞 I/O | 阻塞 | 非阻塞 |
| 线程模型 | 每个请求一个线程 | 少量线程处理 |
| 适用场景 | 传统请求-响应,数据库访问 | 高并发,IO 密集 |
| 社区支持 | 成熟 | 较新 |
选择建议:
- 如果用阻塞数据库/JDBC,Spring MVC 足够
- 如果是高并发网关、IO 密集(如代理、微服务网关),用 WebFlux
- WebFlux 不适合 CPU 密集,不适合复杂的同步事务
五、Spring Boot 性能调优
启动加速
properties
# 1. 关闭不需要的自动装配
spring.autoconfigure.exclude=com.xxx.xxxAutoConfiguration
# 2. 延迟初始化(懒加载)
spring.main.lazy-initialization=true
# 3. 分层编译(C2 分层编译优化)
-XX:+TieredCompilation
# 4. 类数据共享(CDS)
java -Xshare:dump -XX:+UseAppCDS -jar app.jar
# 后续启动加快
# 5. Spring Boot 2.4+ 支持分层 jar 解压
# 解压后启动更快内存优化
java
// 1. 减少不必要的依赖,排除不需要的 starter
<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>
// 2. JVM 参数调优
-Xms1g -Xmx1g # 固定堆大小,避免扩缩容
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m
-XX:+UseG1GC # G1 适合大堆,停顿均匀
// 3. 开启优雅关闭,处理完请求再退出
server.shutdown=graceful并发调优
properties
# 调整 Tomcat 线程池
server.tomcat.max-threads=200
server.tomcat.min-spare-threads=10
# 连接池大小(数据库连接池 HikariCP)
spring.datasource.hikari.maximum-pool-size=10
# 连接池大小不要太大,每个连接占用内存六、常见性能问题
| 问题 | 原因 | 对策 |
|---|---|---|
| 启动慢 | 太多不必要的自动装配 | 排除不需要的自动装配,开启懒加载 |
| 内存占用大 | 堆太大,依赖太多 | 调整 Xmx,排除不必要的依赖 |
| 请求延迟大 | 连接池太小,线程池不够 | 增加连接池大小,检查慢查询 |
| OOM | 内存泄漏,堆太小 | 用 MAT 分析,增加 Xmx,修复泄漏 |
七、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| 组件扫描找不到 | 启动类不在根包 | 启动类放在根包,依赖扫描到所有子包 |
| 自动装配冲突 | 多个自动装配,不知道用哪个 | 用 @ConditionalOnClass 排除,显式排除 |
| 懒加载导致配置问题 | 某些配置依赖提前初始化 | 关键配置类用 @Lazy(false) |
| WebFlux 阻塞事件循环 | 阻塞操作放在 event loop | 把阻塞操作放到 scheduler 线程池 |
相关与延伸
下一篇:Go Gin 后端——路由、中间件、协程模型、context、性能分析;后端框架索引见 index.md。
一句话总结
Spring Boot:@SpringBootApplication 是 @Configuration + @EnableAutoConfiguration + @ComponentScan;自动装配从 META-INF/spring.factories 加载,按 @Conditional 条件过滤;启动过程创建环境、创建容器、refresh 上下文、调用 runner;Spring MVC 适合传统阻塞数据库访问,WebFlux 适合高并发非阻塞 IO 密集;启动加速用排除自动装配、懒加载、CDS 类数据共享;内存优化调整堆大小,排除不必要依赖,连接池控制大小。