前言
JDK 升级对于 Java 应用来说是不得不面对的事情,一方面 Java 生态系统希望 Java 应用能跟上最新 JDK 版本:Oracle 建议将 JDK 的 LTS 版本的发布周期从 3 年调整为 2 年,对于只使用 LTS 版本的应用来说,可以在更短时间内使用最新的技术,但这也意味着版本升级会更加频繁。
Spring Framework 6 只支持 JDK 17。Spring 是大多数企业级应用依赖的基础框架,意味着不得不升级到 JDK 17。
但是另一方面,现实中的 Java 应用的 JDK 升级较为缓慢。JDK 11 从 2018 年发布近 4 年,已升级 JDK 11 仍未达到半数(2022-state-of-java-ecosystem)。而相比之下,JDK 8 发布之后 1 年内可达到 38%,两年达到 64.3%,到 2018 年时近 80%(java-8-adoption-march-2016、jvm-ecosystem-report-2018)。可能的原因是多方面的。例如 JDK 8 在语言层面引入了 Lambda 对开发人员非常有吸引力,而 JDK 11 在语言层面的更新显得可有可无。但是有一点是非常明显的,相比从其它版本升级到 JDK 8(JDK 6/7 升级到 JDK 8 对于应用基本无感),升级到 JDK 11/17 难度会大很多,可能会遇到很多兼容性问题,如:1、删除了一些 API 如 sun.misc.*导致代码出现 ClassNotFoundException。2、Java Version 的 Schema 发生变化导致原来判断 Java 版本的逻辑出现异常。3、用户代码中使用了私有的 API,使用了标记为废弃的 API 等。4、JPMS(Java Platform Module System)的引入导致一些反射代码会无法工作。如果需要升级的应用依赖了成百上千的二方和三方 jar,而这些 jar 可能也存在兼容性问题,更进一步,如果需要升级的应用几十个甚至几百个,那么带来的额外工作量可想而知。正是由于上述的困难,阿里巴巴内部将这些升级的经验通过工具沉淀下来,希望能够通过工具帮忙更多的 Java 应用更高效的升级最新版本 JDK。目前 Eclipse Migration Toolkit for Java(简称“EMT4J”)已经在 Eclipse 社区开源,并通过了 Eclipse Adoptium PMC 评审,作为 Eclipse Adoptium 子项目进行孵化。阿里云也是 Eclipse Adoptium 工作组的战略基石成员,参与 Eclipse Adoptium 社区治理,为 Java Ecosystem 提供完全兼容的、基于 OpenJDK 的高质量 JDK 发行版。EMT4J 目前支持了从 JDK 8 升级到 JDK 11&17 的分析,后续也会不断的更新对于最新的 LTS 版本的支持。EMT4J 架构图如下:
EMT4J——工具使用(场景演示)
开发人员张三接到任务,需要将所在团队负责的 8 个 Java 应用(app-service-1 到app-service-8)从 JDK 8 升级到 JDK 17,那张三在 EMT4J 的帮助下如何升级呢?1、张三下载了 EMT4J 工具到本地,并且在 /home/jdk17 本地安装了目标版本的 JDK 17。2、将 app-service-1~app-service-8 的应用包下载到 EMT4J 所在机器,放在目录 /home/app/deploy,并将 app-service-1~app-service-8 的 JVM 选项放入到 .cfg 的文本文件,放在目录 /home/app/vmoptions。3、运行工具检查:sh ${EMT4J_HOME}/bin/analysis.sh -f 8 -t 17 -j /home/jdk17 /home/app,其中 -f 8 -t 17 表示从 8 升级到 17, -j /home/jdk17 表示目标版本 JDK 的安装目录,/home/app 表示需要检查的应用包以及参数文件。命令执行完成以后,默认会在当前目录生成 report.html。打开检查报告report.html 查看到问题的列表如下:4、张三点击"The schema of java version changed in JDK9"查看问题的详情,看到提示如下具体的类:Location: file:/home/app/deploy/app-service-1/notify-utils-2.2.5.jar, Target: com.app.services1.utils.VersionInfo。5、张三打开 app-service-1 的工程看到如下的代码,下面的代码显然是无法处理类似于 17.0.1 版本号。private final String JAVA_VERSION = System.getProperty("java.version");
private final int getJavaVersionAsInt() {
if (this.JAVA_VERSION == null)
return 0;
String str = this.JAVA_VERSION.substring(0, 1);
str = str + this.JAVA_VERSION.substring(2, 3);
if (this.JAVA_VERSION.length() >= 5) {
str = str + this.JAVA_VERSION.substring(4, 5);
} else {
str = str + "0";
}
return Integer.parseInt(str);
}
6、张三参考报告中的 How to fix 了解到 JDK 9 以后 Java Version 的 Schema 发生了变化,按新的 Schema 修改代码。7、张三按依次参考报告中对其它问题修改。修改完成以后,在开发机器上使用目标版本 JDK 启动验证功能正确性。
EMT4J——工具特性一览
以上使用 EMT4J 工具帮助张三从 JDK 8 成功地升级到 JDK 17,那么 EMT4J 工具具有哪些特性?
1、支持 Java Agent、命令行工具以及 Maven 插件等方式使用- Java Agent 可以获取更多运行时上下文信息,能提供准确调用栈,能发现更多的问题
- 命令行工具方便使用,无须启动应用,但是可能会存在误报
- Maven 插件可以集成在构建阶段,可在开发阶段发现问题
- System ClassLoader 不再是 URLClassLoader 子类
- Java Version 的 Shema 发生变更
- JPMS 需要增加 add-exports 和 add-opens
删除了 Nashorn
删除了RMI 和 Java Applet
部分 Class 无法反射获取 Field
...
3、支持 HTML、TXT 和 JSON 格式的输出
如何参与贡献?
如果您在使用 EMT4J 的过程中,遇到如下的问题:结语:因为目前还有很多的 Java 应用仍然停留在 JDK 8上,所以这些应用正在规划或者正在升级 JDK 中,希望通过 EMT4J 让我们的升级工作更轻松一些。我们在工具中沉淀了阿里巴巴升级 JDK 的经验,但是肯定还有很多我们没有遇到的兼容性问题,另外 JDK 新的版本不断会发布,也会不断有新的兼容性问题出来。我们希望通过开源的方式,能够有更多的开发者参与到工具中,给工具不断增强功能,让更多的 Java 应用升级变得更简单。更多内容 (如何使用、贡献等) 可以参考(或点击阅读原文直达): https://github.com/adoptium/emt4j