当老板让我从 Java8 升到 Java11

article/2025/9/21 8:37:46

老板让我把一个项目从 Java 8 迁移到 Java 11,我该怎么办呢?

最简单的办法,当然是直接强行升级,遇到一个错就改一个错,别看它 low,但是对于一个小型且非核心的项目来说,已经足够了。

当然,对于比较重要的项目,且代码行数不少的情况,最标准的姿势就是对着官方文档,就是这份 Java 11 的迁移说明文档。

https://docs.oracle.com/en/java/javase/11/migrate/index.html

里面详细说明了 Java 8 到 Java 11 可能出现的兼容性问题,并给出了修改措施或建议。

理论上来说,对着官方文档一个字一个字去读,并且把代码的每一行都肉眼扫描一遍,该修改的地方就做出修改,肯定是可以完美迁移的。

但人毕竟不是机器,自己写的代码可能就有上千甚至上万行,还得算上引入的第三方类库,这显然就不是人干的事情了。

所以,就有一款神奇的工具,可以帮我们自动扫描 JDK 升级过程中需要修改或注意的地方,并直接生成一个可视化的 HTML 报告,厉害了!

它是什么

这款工具的名字叫做 EMT4J,即 Eclipse Migration Toolkit for Java,直译过来就是 Eclipse 基金会旗下的,用来迁移的,工具集,为 Java 准备的。

官网地址为:

https://projects.eclipse.org/projects/adoptium.emt4j

官网介绍它的方式非常亲民,直接来了个以 Tom 为主人公的小故事,大概说的是 Tom 准备把项目从 8 迁移到 11,非常痛苦,用上了 EMT4J 后就爽得飞起。

我非常喜欢这种方式,大家感兴趣可以读一读,没有什么难的词汇。

这款工具是阿里写的,捐赠给了 Eclipse 基金会,所以阿里云官方公众号推出过关于介绍它的推文

https://mp.weixin.qq.com/s/9pKGVctSd-phrV4sKqqfxA

不过官网和推文都包含很多宣传色彩,有很多杂乱信息,作为一枚呆萌的开发者,我还是更喜欢看简单粗暴的代码仓库:

https://github.com/adoptium/emt4j

仅仅一张截图,就包含了核心功能,下载地址,快速上手体验这三个开发者最关注的点。

它怎么用

点击下载地址下载好 EMT4J 后,查看它的目录结构,发现非常简单明了直观。

➜  Downloads tree emt4j-0.3
emt4j-0.3
├── bin
│   ├── analysis.bat
│   └── analysis.sh
└── lib├── agent│   ├── emt4j-agent-jdk11-0.3.jar│   └── emt4j-agent-jdk8-0.3.jar├── analysis│   ├── asm-9.2.jar│   ├── commons-io-2.4.jar│   ├── commons-lang3-3.8.jar│   ├── emt4j-analysis-0.3.jar│   ├── emt4j-common-0.3.jar│   ├── gson-2.9.0.jar│   ├── lombok-1.18.8.jar│   ├── mvel2-2.4.12.Final.jar│   ├── slf4j-api-1.7.30.jar│   └── velocity-engine-core-2.3.jar└── maven-plugin└── emt4j-maven-plugin-0.3.jar

如果只使用 javaagent 方式来分析项目,那么对于使用者来说只需要关注 agent 目录下的两个 jar 即可。

从 8 迁移到其他 JDK 就使用:

emt4j-agent-jdk8-0.3.jar

从 11 迁移到其他 JDK 就使用:

emt4j-agent-jdk11-0.3.jar

我们写一个简单的 Hello World 程序,并用 JDK8 编译。

public class Hello {public static void main( String[] args ) {System.out.println( "Hello World!" );}
}

然后对其进行 8 到 11 的迁移分析。

java -javaagent:emt4j-agent-jdk8-0.3.jar=to=11 Hello

对输出结果可视化为 HTML 格式。

sh analysis.sh -o report.html emt4j-XXX.dat

打开这个 HTML 文件,发现输出的结果正符合我们预期。

对嘛,一个 Hello World 程序自然不需要考虑迁移的兼容性问题~

拿一个复杂的项目举例

我们再尝试分析一个较为复杂的项目,依然进行刚刚那几步动作,这回输出的报告有点意思了。

我们就通过目录中的摘要,就可以看到这个项目从 8 迁移到 11 所需要考虑的全部问题了。比如从 JDK 9 java.version 的 schema 发生了变化,点进去。

在如何修复那里,给出了官方说明文档,我们继续点进去。

简单说就是 java.version 这个系统变量所输出的字符串格式发生了变化,你的程序要是依赖这个字符串做截取和判断啥的,就需要小心了。

比如报告中的问题上下文中,就给出了所有可能受之影响的方法,我们举个例子。

在大名鼎鼎的 log4j 中的 AbstractStringLayout 类中有个 isPreJava8 方法,用来判断是否是 Java 8 以前的版本。

// log4j-core:2.10.0
private static boolean isPreJava8() {String version = System.getProperty("java.version");String[] parts = version.split("\\.");try {int major = Integer.parseInt(parts[1]);return major < 8;} catch (Exception var3) {return true;}
}

如果使用 Java 11 来运行这个方法,会得到 true,也就是认为 11 是 8 之前的版本,这显然是不对的,简单 debug 一下就知道错在哪了。

当然,我使用的版本是 log4j-core:2.10.0,我相信大名鼎鼎的 log4j 项目一定在之后的版本修复了这个问题。

果然,在某一次 commit 上就专门修复了这个问题。

修复的方式也很 low,就是判断第一个点前面如果是 1,就按照新的方式做判断,即把点后面的数字作为主版本。

嗯,那看来,把这个项目从 8 升级到 11,最稳妥的方式是连这个使用老版本的 log4j 三方依赖也同时升级了。

什么原理

下面探索一下这个项目的原理,GitHub 官网中给出了一张架构图。

左边是 agent 方式分析运行中的项目,上面是分析静态的 Jar 和 Class 文件等,他们仅仅是解析符号时有所不同。

中间部分是,当符号解析完毕后,都需要读取规则 Rules,这些规则 Rules 就是判断是否会出现兼容性问题的逻辑,如果匹配到了,则记录下来。

右下方是,把刚刚记录下来的兼容性问题,用更友好的方式比如 HTML 的形式输出,给最终的用户看。

所以整个架构还是十分清晰的,重点是里面的细节是如何处理的,我这里只说关键的环节。

agent 方式分析可能不太直观,如果你想了解,可以从这个标准 javaagent 项目的 premain 方法开始看起。

我这里正好了解一下另一种直接静态扫描 class 文件或 jar 文件的检查方式,这个就很直观了。

首先我们故意写一个可以触发上面说的 java.version 格式兼容性问题的代码。

class Hello {public static void main(String[] var0) {System.out.println("hello");System.out.println(System.getProperty("java.version"));}
}

然后把它编译成 class 文件,放入一个 classFiles 文件夹中,作为我们的扫描文件夹。

然后执行 sh 命令,表示检查该文件夹中 8 迁移到 11 的风险项。

sh analysis.sh -f 8 -t 11 -o report.html classFiles

这个 sh 脚本其实就是执行 AnalysisMain 的主方法,并且将上面几个参数作为 args 传入进去。

// org/eclipse/emt4j/analysis/AnalysisMain.java
public class AnalysisMain { public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException {...ReportConfig config = doAnalysis(args, ...);doReport(config, ...);}...
}

所以从这个入口开始看起就好了。

主方法的结构也很简单,doAnalysis 就是对这些 class 文件进行分析,得出结果。doReport 就是将分析结果可视化,比如生成 HTML 文件。

具体调用链我不一一展开,只看很关键的环节。首先 ClassAnalyzer 中的 processClass 方法使用了 ASM 将 class 文件解析为各种符号,保存在 ClassSymbol 对象里。

// org/eclipse/emt4j/analysis/analyzer/ClassAnalyzer.java
protected static void processClass(byte[] classFileContent ...) {ClassSymbol symbol = ClassInspectorInstance.getInstance().getSymbolInClass(classFileContent);...
}

然后,由各种规则文件利用这些符号信息做判断,比如 WholeClassRule,表示需要整个 class 文件信息才能做判断的规则。

@RuleImpl(type = "whole-class")
public class WholeClassRule extends ExecutableRule {...@Overrideprotected CheckResult check(Dependency dependency) {Map<String, Object> mvelMap = new HashMap<>();mvelMap.put("typeSet", dependency.getClassSymbol().getTypeSet());mvelMap.put("methodSet", toMethodIdentifierSet(dependency.getClassSymbol().getCallMethodSet()));mvelMap.put("cpSet", dependency.getClassSymbol().getConstantPoolSet());Object result = MVEL.eval(mvel2Rule, mvelMap);if (result instanceof Boolean) {return ((Boolean) result) ? CheckResult.FAIL : CheckResult.PASS;} else {throw new JdkMigrationException("Mvel2 rule file" + mvel2RuleFile + " must return a boolean result!Now result type is : " + result.getClass());}}
}

这里将刚刚的符号信息取出来,放入 mvelMap 中,分别是 typeSet 类型集合、methodSet 方法集合、cpSet 常量池集合。

接下来使用 MVEL 这个第三方类库进行判断,这是一个可以使用表达式进行匹配判断的工具类,很方便,规则表达式就写在这个 mvel2Rule 里。

这个 mvel2Rule 有很多,其中检查 java.version 这个兼容性问题的表达式写在下面这个文件里。

// emt4j-common/src/main/resources/default/rule/8to11/data/mvel2-rule-getjavaversion.cfg
methodSet.contains('java.lang.System.getProperty') && 
(cpSet.contains('java.version') || cpSet.contains('java.specification.version') || cpSet.contains('java.runtime.version')
)

这个规则表达式很好理解,你不用了解它的写法也能看懂,就是当使用了 

System.getProperty

方法,并且字符串常量池中有

java.version 或 java.specification.version 或 java.runtime.version

时,就视作有兼容性问题。

可以看出,这个判断非常粗糙,就是简单的字符串包含判断而已,由此可见,兼容性问题的判断,也逃脱不了这种方式,不要以为里面利用了什么智能分析方法。

当这个兼容性问题被记录下来后,最终输出 HTML 文件的时候,会通过 ResourceBundle 查看官方文档说明,将详细信息写入 HTML 文件中。

最终就看到了效果,就是这么简单。

再说两句

通过体验和了解这个项目,我们可以学到很多东西,麻雀虽小,五脏俱全。

首先它通过 agent 和 sh 两种方式提供给用户使用,但中间的分析判断逻辑都是共用的。

然后,这个项目使用了专门解析 class 文件的 ASM 工具,把符号信息提取出来方便后面使用。

又使用了 MVEL 作为规则判断的工具,使得规则判断只需要写好表达式即可。

最后输出为 HTML 时,为了查询对应兼容性问题对应的官方说明,使用了 ResourceBundle 查找官方文档说明,由此我们可以继续深入,了解下官方文档的查询规范,而且是从代码层面的,十分严谨。

好的工具就是利用了这么多知名的工具,使自己便利。那我们也可以利用这个项目,做些自己的事情。

比如你做的某款工具,甚至你定制的某款 JDK,需要检查业务代码中是否有兼容性问题,或者你就单纯想扫描下业务代码中是否有什么什么你关心的东西,那么你可以仅仅修改这个项目中的各种规则表达式,并且定制化自己的 HTML 报告格式即可出色完成这个功能。

其它的,如何扫描 class,如何解析 class 符号,如何调用规则进行判断,如何输出渲染 HTML,都不用再自己做了。

我最近就想用它做点事情,等做好了,后面再给大家分享,今天就到这里吧~

------

以后这个号不接任何广告,除非是我真心想推荐的,以后正常文章也不开赏赞,我会在每个月的第一个星期二开,并且留言区和大家一块热闹热闹,要记得来哟~


http://chatgpt.dhexx.cn/article/H5HtHUjO.shtml

相关文章

java11初体验,8 个逆天新特性教你写出更牛逼的代码!

美国时间 09 月 25 日&#xff0c;Oralce 正式发布了 Java 11&#xff0c;这是据 Java 8 以后支持的首个长期版本。 为什么说是长期版本&#xff0c;看下面的官方发布的支持路线图表。 可以看出 Java 8 扩展支持到 2025 年&#xff0c;而 Java 11 扩展支持到 2026 年。 现在大…

一、Java11安装

一、安装 Java11 window64版本傻瓜式安装即可 二、环境变量 1. JAVA_HOME 变量名&#xff1a;JAVA_HOME 变量值&#xff1a;电脑上JDK安装的绝对路径 &#xff1a; C:\Program Files\Java\jdk-11.0.122. 新建/修改 CLASSPATH 变量 变量名&#xff1a;CLASSPATH 变量值&…

Linux下安装java11(亲测)

1.首先下载java11 yum search java-11-openjdk1.1 选择相应版本&#xff08;本人是x86_64&#xff09; &#xff08;ps:如果不知道选择哪个版本可以输入 arch 或者 uname -a 命令查看系统版本信息&#xff09; 1.2 进行下载 yum install java-11-openjdk.x86_64 -y2.查看ja…

JAVA 11.11

JAVA第二天 1.1java中的数据类型(b) java中的数据类型&#xff1a; 基本数据类型 和 对象类型java是一种强语言&#xff0c;严格遵循类型匹配原则。也就是说 我们存储数据的时候 什么样的数据就必须使用什么样的类型去接收。 ​ 对象类型&#xff1a; 无数种 基本数据类…

怎么从 Java8 升到 Java11?

把一个项目从 Java 8 迁移到 Java 11&#xff0c;我该怎么办呢&#xff1f; 最简单的办法&#xff0c;当然是直接强行升级&#xff0c;遇到一个错就改一个错&#xff0c;别看它 low&#xff0c;但是对于一个小型且非核心的项目来说&#xff0c;已经足够了。 当然&#xff0c;…

Java 11~~20

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言Day11——顺序表&#xff08;一&#xff09;顺序表是什么&#xff1f;Java复习&#xff1a;重写与重载1.重写(Override)2.重载&#xff08;Overloading&#xf…

官网下载JAVA的JDK11版本(下载、安装、配置环境变量)

目录 前言必读&#xff1a; 一、下载JDK11 1.先去浏览器搜索 2.选择Products 3.Java 4.往下滑找到Oracle JDK,然后点击 5.往下滑找到Java11&#xff0c;再选择自己的操作系统 6.选择exe这个直接安装的后缀 7.跳出来的弹窗勾选&#xff0c;并点击 8.弹出来一个甲骨文…

Java11安装与配置环境变量保姆级教程

话不多说&#xff0c;我们以java11为例在windows10_X64系统中进行安装 java11下载地址&#xff1a; 链接&#xff1a;https://pan.quark.cn/s/fdf31b287749 提取码&#xff1a;2NNy 安装Java 直接下一步装就完事了 关闭 配置环境变量 找到jdk文件的路径&#xff1b;如图将路…

Java JDK11的下载与安装

前言 本篇文章是基于win10系统下载安装JDK11的教程。 1.下载Oracle JDK 进入Oracle 官网&#xff1a;https://www.oracle.com/java/technologies/downloads/#java11 选择Java11→Winodws→ .exe版本下载 点击下载之后&#xff0c;可能会出现登录界面&#xff0c;输入Oracle…

运用netty框架实现自定义协议并运用于简易聊天

1.什么是netty Netty 是由 JBOSS 提供的一个 Java 开源框架。Netty 提供异步的、基于事件驱动的网络应用程序框架&#xff0c;用以快速开发高性能、高可靠性的网络 IO 程序,是目前最流行的 NIO 框架&#xff0c;Netty 在互联网领域、大数据分布式计算领域、游戏行业、通信行业等…

netty框架的学习

netty框架的学习 1.netty环境的搭建2.netty的特点2.1什么是netty2.2为什么要使用netty3.netty框架的搭建3.1创建一个maven项目3.2导入依赖3.3搭建框架 之前几天的话开始稍微熟悉了一点maven和Springboot框架&#xff0c;从今天开始要正式的开始学习netty框架了。 1.netty环境的…

Netty框架之责任链模式及其应用

Netty框架之概述及基本组件介绍 Reactor网络编程模型解析 前言 在上篇博客介绍完netty框架的基本组件介绍和概述&#xff0c;也跟着代码看了下NioEventLoopGroup的启动过程&#xff0c;以及基于Reactor线程模型的解析&#xff0c;它是开发Netty的核心思想&#xff0c;也是整…

【初识Netty使用Netty实现简单的客户端与服务端的通信操作Netty框架中一些重要的类以及方法的解析】

一.Netty是什么&#xff1f; Netty 由 Trustin Lee(韩国&#xff0c;Line 公司)2004 年开发 本质&#xff1a;网络应用程序框架 实现&#xff1a;异步、事件驱动 特性&#xff1a;高性能、可维护、快速开发 用途&#xff1a;开发服务器和客户端 Netty的性能很高&#xff0…

Netty框架实现TCP/IP通信

项目中需要使用到TCP/IP协议完成数据的发送与接收。如果只是用以前写的简单的socket套接字方法&#xff0c;每次接收发送消息都会创建新的socket再关闭socket&#xff0c;造成资源浪费。于是使用netty框架完成java网络通信。 Netty框架的内容很多&#xff0c;这里只是代码…

在SpringBoot中整合使用Netty框架

Netty是一个非常优秀的Socket框架。如果需要在SpringBoot开发的app中&#xff0c;提供Socket服务&#xff0c;那么Netty是不错的选择。 Netty与SpringBoot的整合&#xff0c;我想无非就是要整合几个地方 让netty跟springboot生命周期保持一致&#xff0c;同生共死让netty能用…

Netty框架介绍及实战

Netty框架模型 NIO 的类库和API繁杂&#xff0c;使用麻烦&#xff1a;需要熟练掌握Selector、ServerSocket、ChannelSocketChannel、 ByteBuffer等。开发工作量和难度都非常大&#xff1a; 例如客户端面临断连重连、 网络闪断、心跳处理、半包读写、 网络拥塞和异常流的处理等…

Netty框架使用

前言 首先在使用Netty框架的时候需要了解Netty是一个什么东西。 Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具&#xff0c;用以快速开发高性能、高可靠性的网络服务器和客户端程序。也就是说&#xff0c;Netty 是一个基于NIO的…

Netty框架简介

Netty框架介绍 早已听说Netty牛逼了&#xff0c;最近有时间学习学习&#xff0c;官网地址&#xff1a;https://netty.io/&#xff0c;Java系的多种服务器/大数据框架&#xff0c;都离不开Netty做出的贡献&#xff0c;例如dubbo&#xff0c;elasticsearch等等&#xff0c;采用的…

netty框架android,隻需五步,即可基於Netty框架實現Android內網推送功能。

隻需五步,即可基於Netty框架實現Android內網推送功能。 一、先引入依賴,客戶端和服務端用的都是同一個依賴netty-all。 Android Studio中Gradle配置: compile io.netty:netty-all:5.0.0.Alpha2 IDEA中Maven配置: io.netty netty-all 5.0.0.Alpha2 二、創建消息模塊包。 目前…