适用读者:想知道"为什么不用配 Tomcat"的人。
前置:S07-B04。
实测环境:Spring Boot 3.3.6 / JDK 17(2026-11-05)。
覆盖旧文:2620(210) 981(88) 979(75) 980(68) 962(89) 1741(85) 321(82) 322(29) 1756(49) 1739(126) = 987 点。
覆盖扩展:E-S07-008(自动配置 SPI)、E-S07-009(内嵌容器)。
上一篇:S07-B04 · Spring MVC:一个请求走过哪些组件
下一篇:S07-B06 · Web 层实战。
1. 一句话结论
Spring Boot = Spring + 自动配置(条件装配)+ 内嵌容器 + 约定优于配置。它的核心机制是"用 @Conditional 决定哪些配置类生效"。
实测(启动日志):
Tomcat started on port 19070 (http) with context path '/'
Started App in 8.281 seconds (process running for 10.181)
两个关键信息:容器是内嵌的(不需要外部 Tomcat);启动8–10 秒主要花在"扫描 + 装配 + 启动容器"。
2. 自动配置怎么生效(E-S07-008)
@SpringBootApplication
├─ @SpringBootConfiguration
├─ @ComponentScan(扫当前包及子包)
└─ @EnableAutoConfiguration
└─ 读取 META-INF/spring/...AutoConfiguration.imports(Boot 3)
→ 一堆 @Configuration 类,各自带 @ConditionalOnClass/@ConditionalOnMissingBean
| 条件注解 | 含义 |
|---|---|
@ConditionalOnClass |
classpath 有某个类才生效(如 DataSource) |
@ConditionalOnMissingBean |
你没有自己定义时才生效(可覆盖) |
@ConditionalOnProperty |
配置项满足才生效 |
"为什么加个 starter 就有一堆 Bean":starter 带来依赖 → 自动配置类因 @ConditionalOnClass 满足而生效 → 创建 Bean。
"怎么覆盖默认行为":自己定义同类型 Bean(@ConditionalOnMissingBean 让位)。
3. 启动流程(A-979/A-980)
① SpringApplication.run()
② 准备 Environment(配置文件、命令行、环境变量)
③ 创建 ApplicationContext(Servlet/Reactive)
④ 加载 BeanDefinition(扫描 + 自动配置)
⑤ refresh():实例化单例、启动内嵌容器、发布事件
⑥ 启动完成(ApplicationReadyEvent)
| 阶段 | 可插手点 |
|---|---|
| ② | EnvironmentPostProcessor、application.yml |
| ⑤ | ApplicationListener、SmartLifecycle |
| ⑥ | CommandLineRunner / ApplicationRunner |
实测启动耗时 8.281s / 9.838s(两次构建);其中 Tomcat 启动在最后一步。
4. 内嵌容器(A-1756,E-S07-009)
| 问题 | 答案 |
|---|---|
| 为什么不用装 Tomcat | 依赖里已有 tomcat-embed-core,SpringApplication 直接启动它 |
| 能换吗 | 能(spring-boot-starter-jetty / undertow,排除 tomcat) |
| 能打 war 吗 | 能(<packaging>war</packaging> + 外部容器) |
实测的构建坑:只引 spring-boot-starter-parent 不够,必须显式声明 spring-boot-maven-plugin,否则:
no main manifest attribute, in target/s07-1.0.0.jar
这是"能编译但跑不起来"的典型——jar 缺少 Main-Class。
5. 配置与 Profile(A-321/A-322)
| 文件 | 说明 |
|---|---|
application.yml |
主配置 |
application-dev.yml |
环境覆盖 |
| 激活 | --spring.profiles.active=dev 或环境变量 |
.yml vs .properties:yml 有层级、可读性好;properties 更"扁平"、无缩进陷阱。团队选一种即可,别混用。
配置优先级(高→低):命令行 > 环境变量 > application-{profile}.yml > application.yml。
6. 五个误区
| 误区 | 真相 |
|---|---|
| "Boot 就是 Spring 加了个启动类" | 核心是条件装配 |
| "自动配置不能改" | @ConditionalOnMissingBean 允许覆盖 |
| "必须用内嵌 Tomcat" | 可换 Jetty/Undertow 或打 war |
| "加 parent 就能打可执行 jar" | 还要声明 repackage 插件 |
| "启动慢是 JVM 的锅" | 多半是扫描范围/Bean 数量/自动配置过多 |
7. 自检
@SpringBootApplication由哪三个注解组成?- 自动配置靠什么决定"是否生效"?
- 怎么覆盖某个自动配置的默认 Bean?
- 为什么不用安装 Tomcat?
- "no main manifest attribute" 说明缺什么?
8. 下一篇
S07-B06 · Web 层实战:校验、异常、日志、文档、监控
机制讲完,下一篇落地:统一响应结构、全局异常、MDC 链路日志、接口文档与监控。
本篇属于系列《S07 · Spring 框架》。旧文来源:A-2620/981/979/980/962/1741/321/322/1756/1739;扩展点 E-S07-008/009。启动日志与 jar 报错为 Spring Boot 3.3.6 实测。