破坏性变更评估
在升级之前,可通过 jdeps 和 jdeprscan 先评估下是否有使用内部类和废弃 API,有一个总的概览。
jdeps 是 Java 自带的命令行工具,可以用来分析依赖关系和生成模块信息文件,这里我们只借用他的其中一项功能。
通过 jdeps --jdk-internals
检查是否有使用内部 API,以下例子显示使用了 sun.net.util.IPAddressUtil
这个 Java 内部工具类,会显示详细的源码类和 jar 包位置。
可以继续使用 Java 中的内部 API,OpenJDK Wiki 页面 Java Dependency Analysis Tool
推荐了某些常用 JDK 内部 API 的替换项。
jdeprscan 也是 Java 自带分析工具,可查看是否使用了已弃用或已删除的 API。使用已弃用的 API 不是阻塞性问题,还能接着跑,但是建议替换掉。使用已删除的 API,那就彻底跑不起来了。
扫描自己的代码中是否有使用废弃 API:
以上例子,com.company.Util 类在调用 java.lang.Double 类的已弃用构造函数。 javadoc 会建议用来代替已弃用 API 的 API。 但是无法解决“error: cannot find class sun/misc/BASE64Encoder”问题,因为它是已删除的 API, 自 Java 8 发布以来,应使用 java.util.Base64。
注意使用 jdeprscan 需要通过 –class-path 指定依赖项,可先执行 mvn dependency:copy-dependencies
命令,此时会 copy 依赖项到 target/dependency
目录。
另外,可在你项目的 maven pom 文件中引入 maven-jdeps-plugin
,如下示例,引入后如果有使用废弃 API,将在 mvn package
的时候直接失败报错,避免有人无意引入废弃 API。
升级兼容方法
利用 Maven 的 profile
机制,根据 JDK 版本号,自动激活不同的配置。
Java 模块化兼容。
你一定见过这种错误。
也一定知道怎么解决了,将没开放的模块强制对外开放,有两个参数选项:
–add-exports 导出包,意味着其中的所有公共类型和成员都可以在编译和运行时访问。
–add-opens 打开包,意味着其中的所有类型和成员(不仅是公共类型)都可以在运行时访问。
两者的区别在于 –add-opens 开放的更加彻底,不仅 public 类型、变量及方法可以访问,就连非 public 元素,也可以通过调用 setAccessible(true) 后也可以访问。简单起见,直接使用 –add-opens 即可。
使用 Maven 命令时,配置 maven-surefire-plugin 插件,参考如下:
在 IntelliJ IDEA 运行程序如果报错,可以通过在 “VM Option” 配置项中,增加 Java 模块化 --add-opens
相关启动参数即可正常启动。
完整 add-opens
列表。
推荐配置
升级到 Java 21 以后以下是根据我们公司常规经验推荐的配置,非普世可用,请根据自己的应用情况臻选。
- 如果在使用 ZGC,推荐启用分代
-XX:+ZGenerational
,对稳定性、吞吐量、内存占用都有很大优化。 - 在很多场景下 G1 仍然是最稳的选择,内存占用比 ZGC 低,CPU 更稳定。大部分场景下小内存应用,并不需要 ZGC。
辅助迁移工具
一些辅助迁移到新版本的工具,仅供参考。
EMT4J 也是一个静态分析工具,可输出分析报告,也可直接 apply 到 git,直接通过 maven 插件、cli 命令行、Java Agent 3 种方式分析。
目前发布比较慢,只有 master 分支支持 Java 21,可以基于 master 分支自己编译构建,也可以使用已 Realease 版本只分析到 Java 17。
可通过 emt4j-maven-plugin 进行检查。增加以下 plugin,执行 mvn emt4j:check
成功后查看报告。
注意 emt4j-maven-plugin 目前版本 0.8.0 比较老,请使用 Java 8 或 Java 17 跑 mvn 命令,版本太高会失败。
不想使用 xml 配置的,可参考以下命令行直接 run plugin。
检查结果错误可能很多,根据优先级修改,比如我的检查结果。
一键升级依赖包,重构源码,入门指导可参考我的另一篇博客:智能代码重构
。 OpenRewrite 更成熟易用。
检查 Java 命令行选项参数有没有问题,识别出已经过时不支持的参数。
Java 参数太多,到 VM Options Explorer - Corretto JDK21
中参照,里面根据 JDK 的版本以及发行商,列出来所有的相关参数,选择好对应发行商的正确版本,就可以搜索或者查看 java 命令支持的所有参数了。
遇见问题和解决办法
参考资料