后端 2026-10-20 1

Spring Boot 4 快一年了:虚拟线程只是开胃菜,真正的换血在这几处

老张

资深系统架构师

封面-Spring Boot 4 快一年了:虚拟线程只是开胃菜,真正的换血在这几处

Spring Boot 4 快一年了:虚拟线程只是开胃菜,真正的换血在这几处

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

划两个重点:

  • 还在 Java 11 上的项目,第一步不是改代码,是先升 JDK。
  • 还在用 Undertow 的项目,这一条是硬伤——官方支持的内嵌容器只剩 Tomcat 11 和 Jetty 12.1。

二、虚拟线程转正:收益是真的,坑也是真的

这是讨论热度最高的一条。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 翻倍,大概率换来的是数据库先跪。


三、自动配置拆包:Jar 瘦身是附赠品,依赖边界才是真收益

以前所有自动配置都塞在一个巨大的 spring-boot-autoconfigure 里,用不用都打包进来。Boot 4 把它按技术域拆成独立模块,出现了 spring-boot-starter-webmvc 这类更细粒度的 starter——Maven Central 上已经能直接拉到。

三个实在的好处:

  • 打包产物更小,镜像体积下来,容器和云原生场景直接受益
  • 依赖边界清晰,莫名其妙的自动配置冲突变少
  • GraalVM 原生镜像构建更快、产物体积更小

代价也很明确:老 starter 的适配没跟上时,你会看到同一能力的两套模块在依赖树里并存。迁移时要核对依赖,不能只改版本号。

老张点评:这条改动对业务代码零影响,但对"镜像体积"和"排查玄学冲突"影响巨大。镜像按 MB 算钱的团队,值得专门评估。


四、真正的隐形炸弹:Jackson 3 成了默认

这一点在 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 或者序列化结果不对。


五、JSpecify 空安全:编译期挡掉一批 NPE

Spring Framework 7 全链路接入 JSpecify 空安全注解(spring-core 7.0.x 已经直接依赖 org.jspecify),框架内置 API 标注了可空与非空。配合支持 JSpecify 的编译器与静态检查工具,一批空指针能在编译阶段就露头,而不是等线上抛 NPE。

这个能力不是强制开启的,但对追求健壮性的团队,属于低成本高回报的一项。


六、API 版本化 + 声明式 HTTP 客户端

Framework 7 带来两个开发体验层面的能力,Boot 4 直接继承:

API 版本控制:框架原生支持接口版本管理,不用再在路径里手写 /v1/、/v2/,由框架统一解析分发,多版本接口共存更干净。

声明式 HTTP 客户端:定义接口 + @HttpExchange 注解就能调外部服务,不用再引 OpenFeign 那套。注意这个能力从 Framework 6.1 就有了,Boot 4 补的是自动配置和链路上下文传递——异步、虚拟线程场景下 trace 不再断。

写内部对接、第三方接口时,样板代码能少一大截。


七、安全:默认更严,但有一条要辟谣

Boot 4.0 的依赖管理里,Spring Security 已经走到 7.0.0,一批过时配置被移除,默认策略更收紧。真实的变化包括:

  • Cookie、请求头的校验策略默认遵循现代安全规范
  • SSL Bundle 能力增强,证书统一管理,LDAP、消息组件都能复用同一份 SSL 配置
  • 一批老旧能力下线:HTTP/2 Server Push、SecurityManager 相关支持等

同时要辟个谣。 网上流传"Boot 4 新增 InetAddressFilter,原生拦截出站内网地址、防御 SSRF"——我在 Spring Framework 7.0.x 的 javadoc 类型索引里搜不到这个类。SSRF 防护还是得自己做:出站白名单、DNS 解析后二次校验、代理层拦截,别指望框架给个开关。

老张点评:安全这块的规律是——默认收紧都是好事,但"框架帮我防了"这种想法,几乎每次都会出事。


八、可观测性:异步终于不丢 trace 了

  • @Async 异步方法自动传递链路上下文,之前的痛点被解决
  • OpenTelemetry 对齐最新语义规范,OTLP 上报配置统一,支持压缩与自定义 header
  • Log4j 增加文件轮转配置支持

微服务和分布式链路排查,比之前省心。


九、顺手带上的几个小东西

  • Kotlin 2 基线:Boot 4.0 管理的 Kotlin 版本已到 2.2.x,协程上下文自动传播,suspend 函数里的 tracing 能正常工作
  • Spring gRPC 1.0 GA:和 Boot 4 同期发布,坐标是 org.springframework.grpc:spring-grpc-spring-boot-starter(当前 1.0.x)——注意它不是 spring-boot-starter-grpc,搜不到别怀疑人生
  • BeanRegistrar:新的 Bean 注册模型,动态注册更灵活,适合平台型、插件化项目

十、到底该不该现在升

给一个直接的判断表:

你的情况 建议
新项目、无历史包袱 直接 4.1.x 起步
IO 密集型接口服务、团队测试完善 值得评估,先灰度
稳定运行多年的核心系统 缓一缓,等生态适配
依赖大量冷门、停止维护的组件 先做依赖盘点,别急
以 CPU 密集计算为主 收益有限,按需再说

如果决定升,建议分三步,别一次动两件事:

  1. 先升 JDK 到 21 或 25,在 Boot 3.5 上跑稳,观察一段时间
  2. 再升 Boot 4,重点 grep com.fasterxml.jackson 的 import 和 javax.* 残留
  3. 最后开虚拟线程,重新压测连接池容量与中间件客户端行为

升级从来不是为了版本号好看,而是看新能力能不能解决你当下的问题。虚拟线程很香,但它不是银弹;模块化拆分和空安全这些改造,是长期的工程收益。


你现在项目在用 Spring Boot 哪个版本?2.x、3.x 还是已经上了 4.x?最看好哪个新特性,或者觉得哪个改动最容易踩坑?欢迎留言聊聊。

温馨提示:任何线上项目升级,务必先灰度、压测、充分回归,不要直接全量上生产。

本文由老张整理编写,信息综合自 Spring Boot 官方文档、GitHub Release 说明与 Maven Central 等公开资料。

分享:
返回文章列表