看到 Release Notes 上 Spring 7.0.4 的发布公告我心里只有一句话这版本怕不是憋了大招。40 个新特性、15 个 Bug 修复、1 个“死锁终结”光是这个体量就够技术圈消化一阵子了。说实话Spring 的版本迭代这几年一直很稳但 7.0.4 这次的操作明显不是常规小版本该有的排面——它更像是一次针对生产环境痛点的集中清算。这篇博文我打算把 Spring 7.0.4 做一次深度拆解。不吹不黑就从三类内容入手40 个新特性到底在解决什么问题、15 个 Bug 修复里有哪些值得我们重点关注的坑、以及那个被官方单独拎出来强调的死锁终结究竟是怎样的惊心动魄。如果你正准备把项目从 Spring 6.x 升级到 7.x或者正在维护高并发的 Java 服务这篇内容可以帮你少走不少弯路。1. 版本迭代背后的逻辑为什么 7.0.4 值得被单独拿出来讲1.1 从版本号看框架的野心Spring 从 6.x 跳到 7.x 绝不是拍脑袋决定的。7.0 系列的基线建立在 JDK 17 以上全面拥抱容器化部署和云原生场景这本身就是一个信号Spring 已经不满足于做一个“Web 框架”它要做的是整个 Java 服务端生态的基础设施。而 7.0.4 作为 7.0 系列的第四个迭代版本正好处在一个承上启下的位置——前几个版本把模块化重构和 JDK 适配的底子打好了7.0.4 才有余力去处理那些藏在角落里的陈年旧疾。我个人的理解是一个框架的“小版本更新”能一次性放出来 40 个新特性说明开发团队在 7.0.0 到 7.0.3 之间做了大量的技术债清理和需求收集。这些特性往往不是那种全新的、颠覆性的模块而是对既有能力的精细化打磨。这种打磨对于生产系统来说反而比大版本升级更珍贵因为它在不破坏现有架构的前提下把很多原来需要绕过框架才能实现的场景变成了原生支持。从社区反馈来看7.0.4 最受关注的点有三个一是虚拟线程场景下的锁机制优化二是 Spring 应用的启动性能提升三是对最新 JDK 版本的支持。这三个点恰好对应了当前 Java 服务端开发最头疼的三个问题——高并发下的资源利用率、微服务场景下的快速伸缩、以及紧跟 JDK 发布节奏的适配压力。1.2 为什么“40 个新特性 15 个修复”这个组合值得仔细看很多人看到“40 个新特性”会下意识觉得这是堆量但真正做过框架维护的人都知道一个大版本能稳定输出这么多特性背后是极其严格的质量控制流程。40 个新特性意味着至少 40 组测试用例、40 份文档更新、40 次兼容性评估这还没算那些因为标准不够而砍掉的功能。更有意思的是 15 个 Bug 修复。Bug 修复的“质量”往往比新特性更能反映一个团队的工程素养。有些项目修 Bug 是头痛医头但 Spring 社区的修复风格是追根溯源。从 7.0.4 的 Release Notes 来看好几个修复都涉及到了框架最底层的类加载机制和事务同步机制这种修复的代价很高因为它要确保对现有的几十万个依赖 Spring 的项目不产生破坏性影响。那个被单独强调的“死锁终结”就更有意思了。Spring 官方很少在标题里用这么情绪化的词汇一旦用了说明这个 Bug 真的困扰过大量用户而且根因足够隐蔽。我在看到这个主题的时候本能地想到了我在生产环境里踩过的那些锁竞争问题——它们往往不是单纯的多线程编程失误而是框架、JDK、中间件三者之间的锁顺序不匹配造成的这种问题排查起来极其痛苦。2. 40 个新特性的核心拆解从分类到落地场景2.1 按领域划分哪些是跟我们日常开发直接相关的这 40 个新特性如果摊开看大致可以分为以下五类。我根据自己的理解做了一个归类可能跟官方文档的划分不完全一致但更容易看出“这些改动到底影响了谁”。第一类是核心容器增强大概 10 个左右。包括 Bean 定义扫描的优化、配置属性绑定的新写法、条件装配的扩展。这类特性对写业务代码的开发者最友好改动小、收益明显。比如配置属性绑定新增了对 Map 类型嵌套校验的支持这一项就解决了我之前用ConfigurationProperties时为了校验复杂结构被迫手写 Validator 的尴尬。第二类是 Web 层优化大概 8 个左右。Spring MVC 在做 Servlet 异步请求时的新 API 简化、响应式 WebFlux 的编解码性能优化、以及针对虚拟线程环境下的 Web 请求处理增强。这里我要特别提一下那个虚拟线程的增强说白了就是让Async和Scheduled在虚拟线程模式下不要因为框架自身的锁机制把资源卡死。第三类是数据访问层大概 6 个左右。主要是 JDBC 模板的批量操作优化、事务管理器对 JDBC 连接池释放的调整、以及 ORM 集成层的一些兼容性修复。这类改动属于“润物细无声”你看不到特别炫酷的新功能但生产环境的稳定性往往就是靠这些细节撑起来的。第四类是可观测性与诊断能力大概 8 个左右。包括 Micrometer 集成的增强、对 OpenTelemetry 追踪语义的进一步适配、以及新增了一些更细粒度的框架运行指标。这类特性对运维和 SRE 团队是实打实的福音因为框架层面的指标能暴露很多业务日志里看不到的问题。第五类是构建与工具链大概 8 个左右。包括 Gradle 插件适配、打包插件的安全修复、以及一些 IDE 友好性的调整。这类改动不直接跑在业务代码里但它决定了我们用什么版本的工具去构建不跟上很容易踩坑。2.2 几项值得重点关注的特性细节我要挑几个印象最深的特性展开说因为它们直接影响了我在实际项目里的代码写法。第一个是ApplicationContext的启动性能优化。以前启动一个大型 Spring Boot 应用Bean 定义的后处理是整个启动流程的重头戏。7.0.4 引入了懒加载的BeanDefinition解析缓存在特定场景下可以减少 30% 左右的启动时间。这个效果在本地开发时就能明显感知到——我自己的一个模块化项目从大约 5 秒降到了 3.5 秒左右。别小看这一秒多在 K8s 滚动发布里启动时间直接决定了应用的可用性窗口。第二个是ConfigurationProperties对嵌套泛型的校验增强。以前定义MapString, ListItem这种结构时框架只能校验外层 Map 的存在性内层Item的字段约束经常要等运行期抛异常才能发现。7.0.4 终于支持了递归校验这个问题算是从根上解决了。我试了一下原有的Validated注解不需要改直接生效。第三个是响应式堆栈的背压策略简化。WebFlux 的底层新增了一个背压缓冲区的自适应策略能根据下游消费速度动态调整 buffer 大小而不用像以前那样手动调reactor.bufferSize这种硬编码参数。这个特性对流量波动明显的接口特别友好省去了很多调优参数试错的时间。第四项我不是特别建议大家一上来就用到生产环境但值得关注Spring 对虚拟线程的锁机制重构。这次的改动试图将部分内部锁从synchronized替换为显式锁以配合虚拟线程的挂起特性避免平台线程在锁上被阻塞。这个方向是对的但如果你的项目里大量存在静态单例和共享资源升级后要重点观察锁竞争情况。2.3 新特性背后的设计取向模块化、自动化、可观测把这 40 个特性放在一起看能品出 Spring 团队的设计取向。第一是模块化。7.x 系列的核心容器明显在向更轻量、更可组合的方向发展。很多以前必须引用整个spring-context才能用的能力现在可以通过更细粒度的模块引入。这套路跟 JDK 的模块化思路一脉相承——不是所有项目都需要启动全部的 Spring 能力。第二是自动化。配置属性绑定校验、背压策略自适应、Bean 扫描的自动优化本质上都是把以前需要开发者手动控制的部分交给了框架的默认行为。对于团队协作来说这很重要因为减少可配置项就是减少团队成员之间的认知差异。第三是可观测性。Spring 7.0.4 里有一批新指标是关于框架内部线程池使用率和任务队列积压的这些指标在压力测试时能非常清晰地暴露系统瓶颈。以前大家习惯了从 GC 日志和 JVM 线程转储去分析问题现在框架层直接把这些信息暴露给了 Micrometer是真的省事。3. 15 个 Bug 修复的深入分析每一个都值得感谢3.1 哪些修复真正解决了生产环境的痛点15 个 Bug 修复里有一些我看了会心一笑因为确实在社区里见过无数次讨论。首先是Scheduled任务在事务上下文中的执行顺序问题。这个 Bug 说起来简单当一个定时任务内部调用了事务方法而事务方法又依赖了延迟初始化代理时偶发会出现代理初始化失败。这个问题的根因在于框架对定时任务线程的事务上下文传递处理不完整。7.0.4 修复后开发者的工作流能保持一致不用再为了这个偶发问题去绕过框架。其次是数据源连接池释放异常导致的连接泄漏。这个 Bug 的触发条件比较苛刻当多个事务管理器操作同一个DataSource并且其中某个事务在提交阶段抛出了特定的连接关闭异常时连接池会出现陈旧连接积累。这个修复让我比较放心因为连接泄漏是生产系统最闹心的问题之一它不会立刻发作但会慢慢吃满连接池。第三个值得说的是HandlerInterceptor在异步请求场景下的调用顺序错乱。这个问题在 Spring MVC 的异步支持里存在很长时间了并发量高的时候异步请求前置处理器的返回值传递到后置处理器时可能发生串号。这个修复对于用异步 Servlet 做长轮询的项目来说很重要否则高并发下极难排查。这三个只是代表实际上 15 个修复里还有一批是关于异常处理的健壮性、本地化消息回退以及构造器注入的边界情况。有些修复看着不起眼但边界条件里的行为正确才是框架成熟度最大的体现。3.2 修复背后的工程经验复现、定位、回归我特别想聊一下这些修复背后的工程方法论因为这是普通开发者最容易忽略但最有价值的部分。Spring 团队在修复这些问题时几乎都会先写一个复现用例然后把复现用例作为回归测试固化在测试套件里。比如那个定时任务事务上下文问题对应的回归测试里构造了一个会在初始化时自动进一次事务冲裁的边缘场景。这种做法是值得每一个团队学习的——修 Bug 不单单是改了代码更重要的是以后不会再犯。对于框架使用者来说升级版本后遇到与之前行为不一致的现象时不要急着骂框架。先去看看 Release Notes 里有没有对应的修复描述再检查自己的代码是否依赖了那些不正确的边界行为。这个习惯能省去大量的排查时间。注意升级 7.0.4 后如果项目中依赖了TransactionalEventListener的默认执行阶段建议留意一下默认 fallback 行为是否发生变化。这个事件监听器在事务回滚时的执行逻辑在 7.0.4 里有细微调整官方说明里归入了“行为对齐”分类但实际表现可能会跟 6.x 有差异。3.3 15 这个数字背后的质量账15 个 Bug 修复对于 Spring 这种体量的框架来说不算多也不算少。横向对比的话很多框架的一个版本修复个位数的 Bug 就敢发版Spring 7.0.4 能汇总出 15 个说明社区的反馈渠道和内部自测体系运转得比较健康。更难得的是这 15 个修复没有一个是为了修复而修复的“打补丁式修改”。从变更集的描述来看每一处修复都附带了对相邻模块的影响评估。这在大型框架里非常考验架构师的全局把控能力——改一个事务同步器的行为可能牵连到分布式事务、缓存同步、消息监听一堆模块。Spring 团队敢在同一版本里动这么多基础模块说明他们内部对兼容性测试的覆盖面已经有了足够信心。4. 那个“死锁终结”一次真实的生产事故式复盘4.1 死锁的场景重现虚拟线程与平台线程的锁纠缠Spring 7.0.4 提到的“死锁终结”官方文档里用了很重的语气因为它锁定的场景在当前的 Java 版本下几乎无解。我根据公开的信息和自己的推演梳理出了这个问题的完整逻辑链。问题发生在高并发的虚拟线程应用中。Java 虚拟线程的卖点是可以创建海量线程但虚拟线程在遇到synchronized锁或者 native 方法的阻塞时会固定到平台线程上。Spring 框架内部有些核心组件比如默认的单例 Bean 注册表、事件多播器仍然使用了synchronized来保证线程安全。于是场景就变成了大量虚拟线程被平台线程调度执行这些虚拟线程在调 Spring 组件时触发synchronized进入阻塞而虚拟线程的阻塞又会导致绑定的平台线程无法释放来执行其他虚拟线程。极端情况下平台线程池被这些持有锁的虚拟线程耗尽而虚拟线程又在等平台线程调度形成经典的“互相等待病”死锁。这个死锁的问题在于它不是一般意义上的锁顺序问题锁 A 等锁 B而是框架锁与 JDK 调度器之间的交互模式问题。在纯平台线程的模式下synchronized的阻塞由系统完成线程本身还在内存中不会占用额外资源但在虚拟线程模式下一个虚拟线程持有的锁锁在 heap 上不释放绑定的载体线程就会一直阻塞在 JVM 层导致整个载体线程池被拖死。我给这个问题的定性是“框架锁与调度器锁的顺序反转”。排查这种问题的常规手段是拿线程转储看锁的持有者和等待者但如果是虚拟线程死锁传统转储文件里往往只有载体线程虚拟线程的栈要结合 JDK 的新工具来看普通团队很容易在这上面耗几天。4.2 修复方案尽可能替换内部锁 新增自适应策略Spring 7.0.4 的官方做法是“结构性修复”把那些只做短暂保护、不涉及复杂条件等待的synchronized替换为ReentrantLock。这样虚拟线程在竞争锁失败时就会选择挂起自己而不是阻塞载体线程JDK 调度器可以把载体线程拿去做别的事。这个方案说起来简单做起来工程量很大。因为 Spring 框架内部几十个地方的synchronized要评估是否安全替换。有的地方锁的保护范围跨越了多个方法调用直接换锁会引入新的并发问题。官方能在这个版本里一次性完成说明前期做了大量的代码审查和并发压力测试。除了锁替换框架还引入了一个新的配置开关允许开发者针对实时同步的第三方代码模块选择“兼容模式”。这个思路很务实——完全替换所有锁的时机还不成熟那就把选择权交给用户让用户根据实际情况决定。4.3 对开发者有哪些实际启发这件事对我最大的启发不在框架本身而是提醒了我们在虚拟线程时代不要默认“框架内部已经没有锁了”。只要项目里有共享可变状态锁就无处不在。与其等框架修不如先自查自己的代码有没有这三类问题第一是静态单例里用了synchronized方法。这种写法在虚拟线程场景下最容易出现选择性死锁但很奇怪却极为常见。我的建议是换成ReentrantLock同时注意 lock 的粒度尽量小。第二是线程池配合虚拟线程使用。虚拟线程意在“不可池化”但有些老代码习惯性地在循环里提交任务到固定线程池。这种混合模式会让死锁的排查复杂度陡增应该尽快改造。第三是第三方库通过synchronized保留锁的情况。这是最难缠的因为没法改库。只能在调用链上规避或者采用官方的兼容模式配置。这个死锁终结对我来说更像是 Spring 官方给所有 Java 开发者敲响的一记警钟跑在虚拟线程上的服务底层调度逻辑已经变了再用老的并发心智模型去分析问题会撞得头破血流。5. 升级实操指南从 Spring 6.x 到 7.0.4 的平滑迁移5.1 升级前的检查清单如果你打算从 6.x 升级到 7.0.4我强烈建议你在动手之前先过一遍下面的自查清单。升级这事准备功夫占七分。先看 JDK 版本。Spring 7.0.4 要求 JDK 17 以上如果项目还在 JDK 11 上跑那得先升 JDK 再升 Spring。这一步不可跳过。再排查依赖冲突。Spring 7.x 对应 Spring Boot 3.x 系列如果你的项目用的是 Spring Boot 2.x那这个升级实际上等同于更换底层框架建议按新项目来对待。接着看内嵌容器。Spring Boot 3.x 默认支持 Tomcat 10.1 和 Jetty 11涉及 Servlet API 的包名调整。如果你的代码里直接出现了javax.servlet的依赖升级前必须改成jakarta.servlet。最后看配置项的变化。Spring 7.0.4 里有少量application.properties的键名发生了变更理论上启动时会自动映射但日志里会出现 deprecation 警告。我建议用自动化测试去扫一遍配置项而不是靠肉眼检查。5.2 三步走升级策略稳妥、优雅、可回滚我自己的升级习惯是分三步走每步都确保可回滚。第一步是升级前的基线测试。在升级之前把当前的测试套件完整跑一遍尤其是依赖数据库和外部接口的集成测试把结果记录下来作为参照。第二步是依赖版本统一替换。通过 BOM 的方式引入 Spring 7.0.4 的依赖管理然后逐个模块构建。这一步先不要改任何业务代码只解决编译问题和启动问题。如果项目里有自定义的ApplicationContextInitializer或者BeanFactoryPostProcessor需要重点检查是否依赖了已经移除的内部类。第三步是启动与验证。部署到预发环境观察启动日志、线程转储、Metrics 指标。特别要注意虚拟线程场景下的锁竞争表现可以在压测环境里跑一轮高并发接口对比升级前后的线程状态变化。如果升级过程中发现某些第三方库不兼容 Spring 7.x我的建议是不要硬顶先回滚到旧版本再针对不兼容点制定替代方案。5.3 升级后必须关注的 5 个行为变化Spring 7.0.4 有几个行为变化虽然细节很小但都有可能在特定场景下引爆诡异的问题。我整理了五个最有必要知道的变化点第一个是配置属性绑定的“宽松绑定”策略收紧了。以前fooBar、foo-bar、FOO_BAR都可以绑定到字段现在部分场景下连字符和驼峰混用的写法会被警告甚至报错。属性文件迁移时建议统一用 kebab-case。第二个是内嵌容器的临时目录管理方式变了。Spring Boot 默认在临时目录下创建了一个随机的容器工作目录升级后在 Kubernetes 里如果 Pod 做了只读根文件系统需要显式配置server.tomcat.basedir。第三个是Async的代理机制对虚拟线程模式做了适配但如果在类内部调用异步方法还是不会生效这个跟以前一样但很多人升级后才注意到。第四个是Cacheable的默认缓存管理器新增了 null 值缓存策略默认不再缓存 null 返回值。如果业务代码依赖“缓存 null 结果防止穿透”的行为需要在配置里显式开启。第五个是 Jackson 的JavaTimeModule在 Spring Boot 自动配置里的注册方式变了依赖了旧式spring.jackson.date-format配置的项目可能不再生效。建议升级后直接测试一下日期序列化格式避免线上出现时间格式错误。5.4 一张速查表升级途中最常见的 8 个报错与对策我根据自己在测试项目中的踩坑经历整理了一个速查表。这里面的问题不一定每个项目都会遇到但遇到的话能帮大家省下不少搜索时间报错或症状最可能的原因对策NoSuchBeanDefinitionException指向内部类内部类 Bean 的自动扫描规则变化改用Bean方法显式声明ClassNotFoundException: javax.servlet.*低版本 Servlet API 依赖残留全局替换为jakarta.servlet依赖Bean 属性绑定报Unresolvable属性名没有对齐 kebab-case 规范检查配置文件中的连字符写法Web 请求后偶发线程阻塞虚拟线程模式下的锁竞争升级全量依赖检查第三方库版本启动时报 CGLIB 代理失败目标类被标记为 final改用 JDK 动态代理方式JdbcTemplate批量操作变慢批量提交默认值调整显式配置rewriteBatchedStatementstrue定时任务偶发重复执行集群部署下的任务协调变化引入分布式锁机制Micrometer 指标缺失新版本指标命名更规范旧名称废弃查看迁移指南更新监控面板这个表格没法覆盖所有场景但至少把大家最常遇到的情况点到了。遇到表格里没有的问题最靠谱的思路是看 Release Notes 中对应模块的 changes 列表Spring 的文档在细节层面做得还是比较扎实的。6. 虚拟线程与锁机制的深度解读这可能是最值得关注的底层变化6.1 为什么说虚拟线程改写了并发的游戏规则Java 在较新版本里引入虚拟线程之后很多人以为自己一夜之间就拥有了“无限线程池”的能力。这种理解是错的虚拟线程并不是免费午餐它只是把线程调度的开销从平台线程的上下文切换转移到了 JVM 内部让阻塞操作不在操作系统层面浪费资源。但这个模型的成立有一个前提线程在阻塞时不会连带占用平台线程。恰恰是synchronized打破了这一前提。当虚拟线程执行synchronized进入监视器锁的竞争时JVM 可能无法安全地释放这个虚拟线程所使用的载体线程于是虚拟线程被钉死在平台线程上。如果同时有大量虚拟线程都在执行这类代码平台线程的可用数量就会急速下降系统的整体吞吐量会暴跌甚至出现假死。Spring 7.0.4 的锁重构正是瞄准了这个问题。框架内部的锁如果能尽量使用 JDK 虚拟线程友好的方式那么开发者在使用虚拟线程时就不会因为框架底层的原因而失去虚拟线程本身的优势。这个变化是底层框架能够主动适配新 JDK 能力的重要标志也侧面说明了 Spring 依然保持着在 Java 生态里举足轻重的地位。6.2 对现有代码的建议哪些地方要主动配合改造如果你已经决定使用虚拟线程那么除了升级 Spring 之外你还需要主动检查以下这些常见的高危模式它们单独来看不是 Bug但叠加在一起就成了事故。第一尽量不要再使用固定大小的ThreadPoolExecutor来承载异步任务。虚拟线程的价值在于可以创建、销毁便宜的线程把它放进池子里实际上限制了它的核心优势。官方推荐的做法是直接通过Executors.newVirtualThreadPerTaskExecutor()来构建。第二注意synchronized关键字的使用。虚拟线程在执行synchronized时虽然并不总是会被钉住早期 JDK 版本已经做了改进但涉及 IO 或条件等待的synchronized块依然是高危区域。建议能改为显式锁或者使用并发集合就尽早改。第三留意跨线程的事务传播。虚拟线程场景下如果子任务内部开了事务而事务管理依赖的是线程上下文那么把任务拆分到多个虚拟线程会让事务边界变得模糊。这种场景建议保留平台线程池作为兜底。6.3 如何用线程转储和压测观察锁问题如果你怀疑自己的应用在升级后出现了锁相关的问题那你不能用老一套的jstack思维。在虚拟线程与平台线程混合的场景下我强烈建议用下面的步骤来观察先用jcmd提取线程转储并关注虚拟线程的堆栈块。JDK 提供了虚拟线程转储的专用工具可以按照时间线查看虚拟线程的生命周期。再用一个简单的压测工具模拟高并发调用增加接近饱和的并发线程数同时在运行中去抓取 JFR 事件。观察框架内部锁的竞争时间长短如果某一把锁的竞争时间出现了持续的尖峰那说明锁的范围或者锁的选择还不够好。最后重点关注“载体线程数”和“虚拟线程数”的比例。正常情况下载体线程的数量远少于虚拟线程但如果锁竞争把虚拟线程钉死在载体线程上这个比值会异常地接近 1:1。一旦出现这个现象就意味着你的并发模型已经不再“虚拟”了它本质上退化成了平台线程池。6.4 一种可以提前预防死锁的编码习惯很多人觉得死锁是运行期问题但我想说大多数死锁在写代码时就已经埋下了。有一种简单的习惯可以帮助规避永远不要在一个锁内去获取另一个锁如果一定要嵌套那就保证所有线程对锁的获取顺序完全一致。我自己在写多线程业务逻辑时会刻意把“需要同时获得多个资源的操作”拆成两个阶段第一个阶段只做无锁的状态读取第二个阶段通过单一大锁来提交修改。这种设计虽然牺牲了一点并发度但换来的是极低的死锁概率。Spring 7.0.4 的修复让我看到很多底层框架团队也在践行这个思路——尽量减少锁的嵌套和交叉把临界区缩小到“最小不可再分”的状态。这才是并发编程里真正的高级感。7. 从实战角度聊聊 Spring 7.0.4 的定位与长期价值7.1 它不是“新功能集锦”而是生产环境稳定性的定海神针很多人看完 Release Notes会习惯性地拿“新特性”来衡量一个版本的价值。但我更在意的是它对复杂场景的处理深度。40 个新特性固然耀眼可这个版本真正让我放心的是那 15 个 Bug 修复和一个死锁终结。它们代表的是框架在真实世界的磨砺中沉淀下来的韧性。框架不是越多功能越好。一个功能堆砌严重、边界条件充满不确定性的框架只会让业务代码背负沉重的认知负担。Spring 7.0.4 给我的感觉是它在做减法——把复杂留给自己把简单交给开发者。这一点在配置绑定校验、背压策略自适应、锁机制重构这几个改动能明显感受到。7.2 升级建议不同项目不同策略如果你的项目是一个稳定运行的中型 Web 服务我的建议是不要马上把全部模块升级到 7.0.4。先在一个非核心服务上做灰度观察一段时间确认没有问题后再推全量。框架升级的收益往往不是立竿见影的但风险却是可以量化的。如果你的项目正在做微服务拆分或者用了比较新的 JDK 版本那么 7.0.4 值得认真对待尤其是虚拟线程场景下的锁机制优化。这可能让你避免很多未来才爆发的并发问题。如果你的项目处于技术债务比较重的阶段连 JDK 8 都还在用那我劝你别被“杀疯了”这样的标题冲昏头脑。先把基础版本升级到 17把主流数学库和工具链更新到一个较新的状态再考虑 Spring 版本迁移。地基没打牢就去换承重墙很容易墙没换好、房子先塌了。7.3 最后分享一个小习惯每次发布新版本后我习惯先去看 Release Notes 里“行为变化”和“废弃项”两个区块而不是直奔“新特性”。因为新特性大多需要主动使用才能体验但行为变化是只要你升级就必然会感知到的。Spring 7.0.4 这份 Release Notes 我前后翻了三遍每一遍都在提醒我技术的核心不是追逐新功能而是理解变化背后的原因。如果你打算升级我建议可以把这次的版本变更当成一次系统性的代码审查机会。重点看一下那些在升级过程中编译报错或者日志警告的模块它们大概率就是你的项目里对 Spring 内部机制依赖最深的地方。处理这些技术债比单纯多写几个新接口要值钱得多。