
2025 年 11 月 20 日,Spring Boot 4.0 正式 GA。到今天,稳定版已经走到 4.1.1,4.0 系列也补到了 4.0.8。
可直到现在,群里还有人问同一个问题:Boot 4 是不是就是"版本号加 1"?
不是。这次是底层生态的集体换代——Spring Framework 7、Jakarta EE 11、Tomcat 11、Jackson 3,四件大事同时发生。业务代码可能一行没改,但依赖树、序列化、容器、原生镜像全都变了。
这篇不翻译文档,只挑开发者最关心、也最容易踩的几处讲清楚。
Spring Boot 4 的硬性门槛:
| 项目 | Spring Boot 4 的要求 |
|---|---|
| JDK | 最低 Java 17,官方兼容上限已到 Java 26 |
| 底层框架 | Spring Framework 7.0.x |
| 默认 Web 容器 | Tomcat 11.0.x(Servlet 6.1) |
| 备选容器 | Jetty 12.1.x;Undertow 已不在支持列表 |
| 包命名 | 全面 jakarta.*,javax.* 不再支持 |
| JSON | 默认 Jackson 3(tools.jackson),Jackson 2 可兼容 |
| 原生镜像 | GraalVM 25 及以上 |
| 构建工具 | Maven 3.6.3+ / Gradle 8.14+ 或 9.x |
划两个重点:
这是讨论热度最高的一条。Boot 3 时代虚拟线程还是试验性玩法,要自己改线程池、封装异步、处理上下文传递;到 Boot 4,它变成一行配置:
spring:
threads:
virtual:
enabled: true
打开之后,Tomcat 请求处理线程、@Async 异步任务、定时调度任务都会跑在虚拟线程上。
对 IO 密集型业务——调第三方接口、等数据库、等 RPC——收益非常直观:一个请求不再独占一个 OS 线程,几十万并发也不用把线程池往上调。
但有三件事必须提前想清楚,否则上线就是事故:
1. CPU 密集型基本无感。 虚拟线程解决的是"等",不是"算"。计算密集的业务开它,只是换了个壳。
2. 连接池会被瞬间打满。 这条最容易翻车。虚拟线程让"等"变得极其廉价,请求涌入的速度远超从前,HikariCP 的 maximumPoolSize 立刻成为新瓶颈,然后就是满屏的获取连接超时。开虚拟线程前,池子容量、超时、限流策略要一起重算。
3. 老中间件客户端不一定适配。 不少 SDK 内部依赖 ThreadLocal 缓存上下文,或者用 synchronized 保护状态。这类问题本地压不出来,只有真流量才暴露。
还有一条时间线上的细节值得记住:Java 24 的 JEP 491 才真正解决了 synchronized 导致的虚拟线程 pinning。也就是说,同一份代码在 JDK 21 上和在 JDK 24/25 上跑虚拟线程,行为并不完全一致——这是很多"我本地测过没问题"最终在线上出怪事的原因之一。
老张点评:虚拟线程是这几年 Java 生态最实在的一次性能红利,但它改的是并发模型,不是业务逻辑。开个开关就指望 QPS 翻倍,大概率换来的是数据库先跪。
以前所有自动配置都塞在一个巨大的 spring-boot-autoconfigure 里,用不用都打包进来。Boot 4 把它按技术域拆成独立模块,出现了 spring-boot-starter-webmvc 这类更细粒度的 starter——Maven Central 上已经能直接拉到。
三个实在的好处:
代价也很明确:老 starter 的适配没跟上时,你会看到同一能力的两套模块在依赖树里并存。迁移时要核对依赖,不能只改版本号。
老张点评:这条改动对业务代码零影响,但对"镜像体积"和"排查玄学冲突"影响巨大。镜像按 MB 算钱的团队,值得专门评估。
这一点在 release notes 里写得相当克制,但影响面可能是全文最大:Boot 4 默认 JSON 库换成了 Jackson 3,包名从 com.fasterxml.jackson.* 变成 tools.jackson.*。
| 维度 | Jackson 2 | Jackson 3 |
|---|---|---|
| 包名 | com.fasterxml.jackson |
tools.jackson |
| Maven 坐标 | com.fasterxml.jackson.core:jackson-databind |
tools.jackson.core:jackson-databind |
| 异常模型 | 大量 checked IOException |
改为 unchecked |
| Boot 4 中的状态 | 通过 jackson-2-bom 保留兼容 |
默认 |
会炸的地方基本集中在三类:
import com.fasterxml.jackson.databind.ObjectMapper 的工具类、公共组件JsonSerializer / JsonDeserializer(接口签名也动了)ObjectMapper 配置的拦截器、日志脱敏、统一响应包装升级时最省事的动作是:先全局 grep 一遍 com.fasterxml.jackson 的 import,再决定是迁移注解,还是短期保留 Jackson 2 双栈(Boot 4 提供了 jackson-2-bom,两者可以共存一段时间)。
这条如果漏了,编译能过,运行时报 ClassNotFoundException 或者序列化结果不对。
Spring Framework 7 全链路接入 JSpecify 空安全注解(spring-core 7.0.x 已经直接依赖 org.jspecify),框架内置 API 标注了可空与非空。配合支持 JSpecify 的编译器与静态检查工具,一批空指针能在编译阶段就露头,而不是等线上抛 NPE。
这个能力不是强制开启的,但对追求健壮性的团队,属于低成本高回报的一项。
Framework 7 带来两个开发体验层面的能力,Boot 4 直接继承:
API 版本控制:框架原生支持接口版本管理,不用再在路径里手写 /v1/、/v2/,由框架统一解析分发,多版本接口共存更干净。
声明式 HTTP 客户端:定义接口 + @HttpExchange 注解就能调外部服务,不用再引 OpenFeign 那套。注意这个能力从 Framework 6.1 就有了,Boot 4 补的是自动配置和链路上下文传递——异步、虚拟线程场景下 trace 不再断。
写内部对接、第三方接口时,样板代码能少一大截。
Boot 4.0 的依赖管理里,Spring Security 已经走到 7.0.0,一批过时配置被移除,默认策略更收紧。真实的变化包括:
同时要辟个谣。 网上流传"Boot 4 新增 InetAddressFilter,原生拦截出站内网地址、防御 SSRF"——我在 Spring Framework 7.0.x 的 javadoc 类型索引里搜不到这个类。SSRF 防护还是得自己做:出站白名单、DNS 解析后二次校验、代理层拦截,别指望框架给个开关。
老张点评:安全这块的规律是——默认收紧都是好事,但"框架帮我防了"这种想法,几乎每次都会出事。
@Async 异步方法自动传递链路上下文,之前的痛点被解决微服务和分布式链路排查,比之前省心。
suspend 函数里的 tracing 能正常工作org.springframework.grpc:spring-grpc-spring-boot-starter(当前 1.0.x)——注意它不是 spring-boot-starter-grpc,搜不到别怀疑人生给一个直接的判断表:
| 你的情况 | 建议 |
|---|---|
| 新项目、无历史包袱 | 直接 4.1.x 起步 |
| IO 密集型接口服务、团队测试完善 | 值得评估,先灰度 |
| 稳定运行多年的核心系统 | 缓一缓,等生态适配 |
| 依赖大量冷门、停止维护的组件 | 先做依赖盘点,别急 |
| 以 CPU 密集计算为主 | 收益有限,按需再说 |
如果决定升,建议分三步,别一次动两件事:
com.fasterxml.jackson 的 import 和 javax.* 残留升级从来不是为了版本号好看,而是看新能力能不能解决你当下的问题。虚拟线程很香,但它不是银弹;模块化拆分和空安全这些改造,是长期的工程收益。
你现在项目在用 Spring Boot 哪个版本?2.x、3.x 还是已经上了 4.x?最看好哪个新特性,或者觉得哪个改动最容易踩坑?欢迎留言聊聊。
温馨提示:任何线上项目升级,务必先灰度、压测、充分回归,不要直接全量上生产。
本文由老张整理编写,信息综合自 Spring Boot 官方文档、GitHub Release 说明与 Maven Central 等公开资料。