前言
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 11 积极性不高呢?
可能的原因是多方面的。例如 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 ) 的引入导致一些反射代码会无法工作。
5、删除了 J2EE 相关的包。
如果需要升级的应用依赖了成百上千的二方和三方 jar,而这些 jar 可能也存在兼容性问题,更进一步,如果需要升级的应用几十个甚至几百个,那么带来的额外工作量可想而知。
正是由于上述的困难,阿里巴巴内部将这些升级的经验通过工具沉淀下来,希望能够通过工具帮忙更多的 Java 应用更高效的升级最新版本 JDK。
EMT4J 简介
目前 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 版本的支持。
目前支持通过如下 3 种方式使用:
- Java Agent
- 命令行工具
- Maven插件
EMT4J 架构图如下:
EMT4J —— 工 具使用( 场景演示 )
以一个常见的场景来说明工具的使用:
开发人员张三接到任务,需要将所在团队负责的 8 个 Java 应用(app-service-1 到app-service-8)从 JDK 8 升级到 JDK 17,那张三在 EMT4J 的帮助下如何升级呢?
具体升级操作我们分以下七步走:
1、张三下载了 EMT4J 工具到本地,并且在 /home/jdk17 本地安装了目标版本的 JDK 17。
2、将 app-service-1app-service-8 的应用包下载到 EMT4J 所在机器,放在目录 /home/app/deploy,并将 app-service-1app-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 插件可以集成在构建阶段,可在开发阶段发现问题
2、支持多种潜在不兼容性问题分析
- JDK 8 到 JDK 11
- JDK Internal API 的使用
- System ClassLoader 不再是 URLClassLoader 子类
- Arrays.asList 返回类型变化
- Java Version 的 Shema 发生变更
- JPMS 需要增加 add-exports 和 add-opens
- 时区数据变更为 CLDR 引起相关不兼容
- Pattern.compile 的 API 变更
- JVM 选项变更
- ...
-
JDK 11 到 JDK 17
-
删除了 Nashorn
-
删除了RMI 和 Java Applet
-
部分 Class 无法反射获取 Field
-
...
3、支持 HTML、TXT 和 JSON 格式的输出
如何参与贡献?
如果您在使用 EMT4J 的过程中,遇到如下的问题:
- 工具应该发现的兼容性问题,但是实际没有发现
- 工具报告的问题上下文不准确,不方便查找问题在哪里
- 工具报告的问题描述不清晰,难以指导如何修改
- 增加一些新的功能,比如工具支持其它一些格式
- ...
都可以通过如下的方式参与贡献:
- 创建 issue 描述您遇到的问题
- 自己 Fork 以后修改测试后,并通过 PR 合入 master
结语: 因为 目前还有很多的 Java 应用仍然停留在 JDK 8上,所以这些应用正在规划或者正在升级 JDK 中,希望通过 EMT4J 让我们的升级工作更轻松一些。
我们在工具中沉淀了阿里巴巴升级 JDK 的经验,但是肯定还有很多我们没有遇到的兼容性问题,另外 JDK 新的版本不断会发布,也会不断有新的兼容性问题出来。我们希望通过开源的方式,能够有更多的开发者参与到工具中,给工具不断增强功能,让更多的 Java 应用升级变得更简单。
更多内容 (如何使用、贡献等) 可以参考 (或点击阅读原文直达) :
— — 完 ——