应使用jdeprscan扫描已编译字节码识别废弃API,区分forRemoval=true必须修改与仅标记deprecated可暂缓两类问题,并配合jdeps分析内部API及模块依赖,辅以EMT4J生成含迁移建议的全链路兼容性报告。

用 jdeprscan 扫描废弃 API 调用
直接运行 jdeprscan 是最轻量的起点,它不依赖源码,对已编译的 .jar 或 classes/ 目录生效。重点不是“有没有警告”,而是区分两类问题:
- 使用了
@Deprecated(forRemoval = true)的 API(如javax.xml.bind.*)——必须改,JDK17 已移除 - 仅标记
@Deprecated但未设forRemoval(如部分java.util.Date构造器)——可暂缓,但需记录
执行示例:jdeprscan --release 17 target/myapp.jar
注意加 --release 17,否则默认按当前 JDK 版本解析,可能漏掉 JDK17 特有弃用项。
用 jdeps 分析内部 API 和模块依赖
jdeps 能暴露更隐蔽的风险,尤其是反射或类加载绕过模块封装的场景。常见误判点是:工具报 sun.misc.Unsafe,但实际调用来自 Lombok 或 Netty——不能只看包名,得定位到具体调用栈。
- 检查 JDK 内部 API:
jdeps --jdk-internals target/myapp.jar - 检查模块间隐式依赖:
jdeps --multi-release 17 --module-path lib/ target/myapp.jar - 若项目含
module-info.java,务必加--check参数验证模块声明完整性
特别注意:jdeps 不检测运行时反射调用,这类问题要靠启动时加 --illegal-access=deny 触发失败再排查。
跑 EMT4J 做全链路兼容性快照
EMT4J 是面向企业级迁移的集成工具,比单个 JDK 工具更贴近真实部署环境。它会自动合并 jdeprscan、jdeps 结果,并标记第三方库风险等级(比如 “Log4j 2.17.1 支持 JDK17,但 2.16.0 不支持”)。
- 命令中
-f8 -t17必须显式指定源/目标版本,否则默认按当前 JDK 推断,易出错 - 报告里标为 “HIGH” 风险的条目(如使用
com.sun.net.httpserver)要优先处理 - 若项目分多个子模块,别只扫主
jar;用-r参数递归扫描整个lib/目录
它生成的 HTML 报告里,“Migration Steps” 栏会直接给出替换建议(例如 “将 javax.activation.DataSource 替换为 jakarta.activation.DataSource”),比手动查文档快得多。
验证 JVM 参数和 GC 行为差异
JDK17 默认启用 ZGC(Linux x64)且废弃了 PermGen 相关参数,老项目配置的 -XX:MaxPermSize 会直接启动失败。这不是代码问题,但属于测试清单里最容易被忽略的一环。
- 清理所有已废弃参数:
-XX:MaxPermSize、-XX:+UseParallelOldGC(JDK9+ 默认并行)、-Djava.ext.dirs - 对比关键指标:用
jstat -gc看 GC 频次与耗时,JDK17 的 G1 默认停顿目标是 200ms,但若业务峰值请求密集,可能需调-XX:MaxGCPauseMillis=100 - 容器环境必加:
-XX:+UseContainerSupport,否则 JVM 可能无视 cgroup 内存限制,导致 OOMKilled
真正的坑往往不在代码里——某个 startup.sh 脚本里残留的 -XX:ReservedCodeCacheSize=256m 在 JDK17 下会因 CodeCache 管理机制变化而引发 JIT 编译失败,这种细节只能靠覆盖式启动测试暴露。


















