本节目标:搞清 Spring Boot 4.0 与 4.1 究竟改了什么、哪些改动会伤到存量代码,并形成「4.x 现在能不能用」的判断。
适用版本:Spring Boot 4.1.x(Java 21)
1.2 Spring Boot 4 带来了什么
上一节末尾那支团队已经接受了「用 Boot 重构」,但紧接着冒出一个新问题:网上教程一半是 3.x、一半是 4.x,到底跟哪条线? 要回答这个,得先知道 4.x 和 3.x 的差距有多大。答案是:这是 Spring Boot 历史上少见的「大版本重构」,改动幅度接近 2.0 到 3.0 那次。
1.2.1 一次大版本的由来
Spring Boot 3.0(2022 年)的核心任务是 Jakarta 化:把 javax.* 全面换成 jakarta.*,并把基线抬到 Java 17。那次是「换命名空间」。
Spring Boot 4.0(2025 年)的任务是 模块化:把一个巨大的 spring-boot-autoconfigure 拆成几十个按技术划分的小模块。它要解决的是一个积累多年的结构问题——所有自动配置挤在一个 JAR 里,谁也不知道某段配置属于哪个技术、被谁引入。
这次重构带来两个直接后果:包名大面积变化、starter 大面积改名。这也是为什么 4.x 的学习资料看起来和 3.x「像但不完全像」。
1.2.2 最大的破坏性变更:模块化重构
在 3.x 里,几乎所有自动配置都躺在同一个模块 spring-boot-autoconfigure 中,根包是 org.springframework.boot.autoconfigure.*。4.0 把它按技术拆开,形成一套规整的三段式规则:
| 维度 | 规则 | 例子 |
|---|---|---|
| 模块名 | spring-boot-<technology> | spring-boot-tomcat |
| 根包名 | org.springframework.boot.<technology> | org.springframework.boot.tomcat |
| Starter 名 | spring-boot-starter-<technology> | spring-boot-starter-tomcat |
| 测试模块 | spring-boot-<technology>-test | spring-boot-jackson-test |
| 测试包 | org.springframework.boot.<technology>.test | org.springframework.boot.jackson.test |
这套规则一旦记住,你看到任何一个 4.x 的包名或 starter,都能立刻推断出它属于哪个技术。
另一个容易被忽略的影响:以前某些功能只需要引第三方依赖就能用,4.0 起必须显式引 starter。最典型的是数据库迁移工具:
<!-- 3.x:只引 Flyway 本体即可,Boot 会自动配置 -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<!-- 4.x:必须引 starter,否则自动配置不生效 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-flyway</artifactId>
</dependency>
Liquibase 同理,改为 spring-boot-starter-liquibase。
1.2.3 实测日志里的证据
模块化到底改了什么?启动日志是最直接的证据。下面是我在本机(JDK 21.0.12.1 + Maven 3.9.12)跑 4.1.1 时,Tomcat 初始化那几行的真实输出:
2026-10-09T15:42:07.027+08:00 INFO 43496 --- [ main] o.s.boot.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2026-10-09T15:42:07.039+08:00 INFO 43496 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2026-10-09T15:42:07.039+08:00 INFO 43496 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/11.0.24]
2026-10-09T15:42:07.285+08:00 INFO 43496 --- [ main] o.s.boot.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
注意 logger 名那一列:o.s.boot.tomcat.TomcatWebServer。同一段逻辑在 3.5.16 上,包名是旧的:
| 场景 | 3.5.16 的 logger 名 | 4.1.1 的 logger 名 |
|---|---|---|
| Tomcat 启动 | o.s.b.w.embedded.tomcat.TomcatWebServer | o.s.boot.tomcat.TomcatWebServer |
| 优雅停机 | o.s.b.w.e.tomcat.GracefulShutdown | o.s.boot.tomcat.GracefulShutdown |
o.s.b.w.embedded.tomcat 展开是 org.springframework.boot.web.embedded.tomcat,属于 3.x 的「一切都在 boot.web 下」。4.x 则把 Tomcat 相关全部归到 org.springframework.boot.tomcat 模块。包名变化不是审美问题,它意味着你的 logging.level 配置、日志过滤规则、甚至反射代码都可能需要同步改。
1.2.4 Starter 改名表
4.0 起,一批 starter 改了名。旧名仍然保留但已废弃,新项目应一律用新名:
| 废弃的旧名 | 4.x 新名 |
|---|---|
spring-boot-starter-web | spring-boot-starter-webmvc |
spring-boot-starter-aop | spring-boot-starter-aspectj |
spring-boot-starter-oauth2-client | spring-boot-starter-security-oauth2-client |
spring-boot-starter-oauth2-resource-server | spring-boot-starter-security-oauth2-resource-server |
spring-boot-starter-oauth2-authorization-server | spring-boot-starter-security-oauth2-authorization-server |
spring-boot-starter-web-services | spring-boot-starter-webservices |
spring-boot-starter-tomcat(war 部署) | spring-boot-starter-tomcat-runtime |
改名逻辑有迹可循:Web MVC 与 WebFlux 分家,所以 web 要明确成 webmvc;OAuth2 相关统一挂到 security 前缀下;web-services 去掉连字符。迁移期如果想少改代码,可以用过渡 starter:
<!-- 迁移期过渡:一次性把旧 starter 全部映射回新模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-classic</artifactId>
</dependency>
spring-boot-starter-test-classic 同理,用于测试侧。但过渡 starter 只是权宜之计,正式项目应尽早换成新名。
1.2.5 Jackson 3:影响面最广的一次升级
如果说模块化改的是「框架内部结构」,Jackson 3 改的就是「你每天写业务代码时会碰到的东西」。JSON 序列化在 Web 项目里无处不在,这次升级影响面极大。
| 项目 | 3.x(Jackson 2) | 4.x(Jackson 3) |
|---|---|---|
| 核心包名 | com.fasterxml.jackson | tools.jackson |
| 注解包 | com.fasterxml.jackson.annotation | 不变,仍在 com.fasterxml.jackson.annotation |
| 自动配置用的类 | ObjectMapper | JsonMapper / XmlMapper |
| 自定义 builder | Jackson2ObjectMapperBuilderCustomizer | JsonMapperBuilderCustomizer |
| 组件注解 | @JsonComponent | @JacksonComponent |
| Mixin 注解 | @JsonMixin | @JacksonMixin |
包名从 com.fasterxml.jackson 变成 tools.jackson(只有 jackson-annotations 例外,仍留在老包),这意味着你项目里所有 import com.fasterxml.jackson.databind.* 都要改。更关键的是行为变化:
- 自定义
ObjectMapperbean 不再能替换自动配置。3.x 时代「自己 new 一个ObjectMapper塞进容器」就能覆盖默认行为,4.x 里这招失效,要改用JsonMapperBuilderCustomizer。 - 模块自动注册策略变了。Jackson 3 会扫描 classpath 上所有模块并注册,而 3.x 只注册知名模块。想关掉可设
spring.jackson.find-and-add-modules=false。 - 属性重新分组:原来分散在 read/write 两组下的序列化属性,统一并入
spring.jackson.json.read/.write命名空间。
如果迁移期实在被卡住,4.x 提供了逃生舱:
# 临时退回 Jackson 2 的行为(需额外引入 spring-boot-jackson2 模块)
spring:
jackson:
use-jackson2-defaults: true
1.2.6 平台基线整体抬升
4.x 不只是改包名,它把整条技术栈的基线都往上抬了一档。写代码前必须对齐这些前提:
| 组件 | 4.x 基线 | 3.5.x 对照 |
|---|---|---|
| Java | 17+(本系列用 21) | 17+ |
| Kotlin | 2.2+ | — |
| GraalVM native-image | 25+ | — |
| Jakarta EE | 11 | 10 |
| Servlet | 6.1 | 6.0 |
| Spring Framework | 7.x | 6.2.x |
Servlet 6.1 这个基线有个直接后果:一部分旧容器实现被淘汰,不再受支持。想用非 Tomcat 的容器,可选 Jetty 12.1。同时 Web MVC starter 默认内嵌的 Tomcat 版本也从 10.1 升到了 11.0。
Spring Framework 7.0 带来的配套大版本升级同样重要:Spring Security 7.0、Spring Data 2025.1、Hibernate 7.2、Hibernate Validator 9.0、HikariCP 7.0、Micrometer 1.16(4.1 为 1.17)。这些不是 Boot 自己的版本号,而是它协调好的一整组依赖——这正是 BOM 的价值。
1.2.7 4.0 的其他新增能力
除了重构与改名,4.0 也加了不少新东西:
- HTTP Service Clients:用
@HttpExchange接口式声明调用远程服务,取代手写RestTemplate模板代码。 - API Versioning:通过
spring.mvc.apiversion.*做接口版本管理,不用再自己拼/v1/路径。 JmsClient:JMS 的现代化客户端。spring-boot-starter-opentelemetry:可观测性能力进一步标准化。@ConfigurationPropertiesSource:更细粒度地指定配置来源。- Kotlin Serialization starter:Kotlin 项目可以不用 Jackson。
RestTestClient:测试侧的新 HTTP 客户端。
这些能力中,API Versioning 与 HTTP Service Clients 对日常开发影响最大,后续章节会分别展开。
1.2.8 测试写法的同步迁移
大版本除了加功能,也会顺手清理历史包袱。对日常开发影响最直接的,是测试注解的更换。3.x 时代用来注入 Mock 与 Spy 的那两个注解已被彻底移除,取而代之的是 Mockito 系列的新注解,而且新注解不能用在 @Configuration 类里。
同时,@SpringBootTest 的行为也收紧了:它不再自动装配 MockMvc,也不再自动提供 TestRestTemplate。要写 Web 层测试,必须显式补上对应的自动配置注解:
@SpringBootTest
@AutoConfigureMockMvc // 4.x 必须显式声明,否则 MockMvc 注入失败
class OrderControllerTest {
@Autowired
private MockMvc mockMvc;
}
4.x 还新增了 RestTestClient,配合 @AutoConfigureRestTestClient 作为测试侧 HTTP 客户端的新选择。这些变化集中体现在第 17 章的测试章节,本节先建立「4.x 的测试写法与 3.x 不同」这个印象。
除此之外,一批使用率偏低的集成方式与旧打包方式也在 4.0 被清理。涉及非 Tomcat 容器选型、消息驱动集成或自定义 jar 加载方式的团队,升级前需要先确认自己是否受影响,具体的迁移对照清单在第 11 章给出。
1.2.9 4.1 的新增亮点
如果说 4.0 是「重构」,4.1 更像「在重构后的地基上加功能」。本系列主线用的就是 4.1.x:
- Spring gRPC 支持:官方首次把 gRPC 纳入一等公民,配 starter 即可。
- Jackson 工厂配置与 customizer:补上 4.0 迁移时留下的自定义缺口。
spring.config.import指定编码:解决配置文件乱码的老问题。- HTTP 客户端 cookie 配置:
RestClient等客户端可集中管理 cookie。 - SSRF 防护
InetAddressFilter:为出站请求提供地址过滤,安全侧的重要补充。 @Async上下文传播:异步线程能继承调用方的上下文。@RedisListener自动配置:Redis 消息监听更省事。- 惰性 JDBC 连接获取:
spring.datasource.connection-fetch=lazy,配合虚拟线程时很有用。 - OpenTelemetry 环境变量与 sampler/limits、info 端点扩展(
process.*)、Log4j 文件轮转。
其中 gRPC 与 惰性 JDBC 连接获取 是两个值得单独留意的能力,前者打开了服务间通信的新选择,后者直接关系到虚拟线程场景下的连接池效率。
1.2.10 4.1 的额外破坏性变更
升级到 4.1 时,除了 4.0 的变更,还要注意:
- 4.0 中废弃的类、方法、属性已被移除——也就是说,从 3.x 直接跳到 4.1 时,4.0 给的过渡期已经结束了。
layertoolsjar 模式移除,改用tools模式(涉及 Docker 分层构建脚本)。-DskipTests不再跳过测试的 AOT 处理,要跳过 AOT 得用maven.test.skip。这条对用 AOT / native 的团队影响直接。- Apache Derby 支持废弃;jOOQ 3.20 要求 Java 21+。
1.2.11 那么,4.x 现在适合谁用
回到那支团队的选型问题。基于上面的清单,可以给出比较明确的判断:
| 场景 | 建议 |
|---|---|
| 全新项目,团队能接受 Java 17+ | 直接用 4.1.x。没有历史包袱,新名新写法一次到位 |
| 教学 / 学习 | 用 4.1.x。学新不学旧,避免先学废弃写法再改 |
| 小规模存量项目,升级成本可控 | 可以规划升 4.1,但先做依赖与 Jackson 影响面评估 |
| 重度依赖 Jackson 2 定制行为的项目 | 谨慎,先把 ObjectMapper 定制改成 JsonMapperBuilderCustomizer 再升 |
| 依赖已被移除的低使用率功能 | 先找替代方案,替代不了就留在 3.5.x |
一句话:4.x 已经过了「能不能用」的阶段,现在的问题是「你的项目准备好没有」。
1.2.12 什么场景该等一等
不是所有团队都该立刻上 4.x。下面这些情况,留在 3.5.x 是理性选择:
- 受监管行业、有强制版本冻结流程:新大版本还没经过完整的合规审查周期,贸然升级反而增加审计成本。
- 深度使用已被移除的旧组件:迁移工作量大,收益不成正比。
- 第三方生态尚未跟进:某些商业中间件、内部 SDK 可能还没适配 Servlet 6.1 或 Jackson 3。
- 团队没有专职的构建/依赖负责人:大版本升级中的版本冲突排查需要有人专门盯。
需要说明的是:3.5.x 仍是受支持的分支,继续用并不等于落后。选型要算的是「升级成本」与「升级收益」的账,而不是「版本号大小」。
1.2.13 学完本节你应该能回答的问题
- 4.0 模块化的三段式命名规则是什么?(1.2.2)
- 从日志里怎么一眼看出项目跑在 3.x 还是 4.x?(1.2.3)
spring-boot-starter-web在 4.x 叫什么?(1.2.4)- Jackson 3 里,为什么「自定义
ObjectMapperbean」不再生效?(1.2.5) - 4.x 的 Servlet 与 Jakarta EE 基线分别是多少?(1.2.6)
- 哪三类项目适合立刻上 4.x,哪三类该等一等?(1.2.11、1.2.12)
把这几个问题答顺,你就具备了独立判断「这个项目能不能升 4.x」的能力,而不用再依赖别人的结论。
小结
- Spring Boot 4.0 是一次模块化重构,按技术拆分了原本庞大的自动配置模块,带来包名与 starter 名的系统性变化。
- 三段式规则:模块
spring-boot-<tech>、包org.springframework.boot.<tech>、starterspring-boot-starter-<tech>;实测日志里o.s.boot.tomcat.TomcatWebServer就是证据。 - Starter 改名中,Web MVC 从
web变为webmvc;迁移期可用spring-boot-starter-classic过渡。 - Jackson 3 把包名迁到
tools.jackson,ObjectMapper换成JsonMapper,且自定义 bean 不再覆盖自动配置。 - 平台基线抬到 Java 17+、Jakarta EE 11、Servlet 6.1、Spring Framework 7;部分旧容器实现被淘汰。
- 4.1 在重构地基上加了 gRPC、API Versioning 相关增强、惰性 JDBC 连接获取等能力,但同时也移除了 4.0 的过渡接口。
- 新项目与教学用 4.1.x;受监管、依赖已移除组件、生态未跟进的存量项目,留在 3.5.x 是理性选择。
知道了 4.x 改了什么,下一个问题自然是:3.5.x 与 4.1.x 到底差在哪几个具体数字上,我们该按什么标准二选一? 下一节给出逐项对照表和决策树。
阅读导航:上一节:1.1 定位、生态与它解决的问题 · 下一节:1.3 版本线的选择 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。