结论:整体路线是对的,但真正吃时间的是第四步——被移除的模块和内部 API,我把这块的替换清单和几个必踩的坑补上,你照着填就行。

**javax 相关的替换清单(Java 9+ 移除,Jakarta 9 起包名变 jakarta.*)**

  • javax.xml.bind.* → jakarta.xml.bind:jakarta.xml.bind-api + org.glassfish.jaxb:jaxb-runtime(两个都要,只加 api 会在运行时报 “Implementation of JAXB-API has not been found”)
  • javax.annotation.*(@PostConstruct/@Resource)→ jakarta.annotation:jakarta.annotation-api
  • javax.mail.* → jakarta.mail:jakarta.mail-api + angus-mail
  • javax.ws.rs.* / JAX-WS → CXF 3.6+ 或直接换 Spring
  • CORBA 那批没救,只能找替代方案

⚠️ 注意:升级 Boot 3 时是 javax.* → jakarta.*,不是补依赖就行,老 jar 里仍是 javax 包名的组件(如老 Shiro、老 CXF)会和 Spring 6 不兼容,这块最好单独开一个 PR。

反射类库要加 --add-opens
JDK 17 起强封装默认生效,fastjson1、hessian、cglib、老版 Jackson、Hutool 的部分反射都会报 InaccessibleObjectException。启动参数加:--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED,先跑通再逐个换成新版本依赖,别长期挂着。

三个容易忽略的运行时差异

  1. JDK 18 起 file.encoding 默认 UTF-8(JEP 400)。Windows 上读 GBK 配置/CSV 会乱码,别指望 -Dfile.encoding=GBK 兜底(JDK 18+ 语义已变),要么显式传 Charset,要么 -Dfile.encoding=COMPAT 过渡。
  2. CMS 在 JDK 14 已移除,启动脚本里还留着 -XX:+UseConcMarkSweepGC 会直接起不来;-XX:MaxPermSize 同理。21 上想尝鲜可以试 -XX:+UseZGC -XX:+ZGenerational。
  3. 虚拟线程在 21 里碰到 synchronized 会 pin 住载体线程,用之前先搜一遍代码里的同步块和 ThreadLocal 缓存。

回滚方案:镜像里同时保留 JRE 8 和 21,用灰度切流量;Gradle 建议先到 8.x、Maven 到 3.9、Lombok 至少 1.18.30(低于这个版本编 21 会直接崩),这几个是前置条件,很多人卡在这。

帖子后面没贴完,等你把“第五步上线验证”补上我再接着看。