Ant + WebLogic 环境下的 JDK8 → JDK17 迁移调查

使用 jdeps / jdeprscan 进行依赖关系分析的实践记录


1. 整理调查对象

本次处理的是日本业务系统中常见的以下构成:

  • Java EE 系统
  • Ant 构建
  • WebLogic Server 12c(对应 JDK8)
  • Eclipse 开发环境
  • 无依赖管理工具(不使用 Maven / Gradle)

注意: WebLogic Server 对 JDK17 的支持需要 14.1.1.0 → 14.1.2.0 以上版本。请确认现有的 WebLogic 版本,必要时请考虑升级。

本次工作是 JDK8 → JDK17 迁移的前期调查。

首先进行的是「确定扫描对象」的整理。

本系统以 EAR 格式进行分发,内部包含:

  • WAR
  • EJB jar

等多个模块。

因此,首先展开 EAR,将本次的调查对象整理为以下两类:

  • classes 目录(已编译的 class 文件)
  • 各种 jar 文件

也就是说,本次的任务是:

以从 EAR 分解得到的 class / jar 为对象,调查与 JDK17 的不兼容性。


2. jdeps 与 jdeprscan 的作用

在开始扫描之前,先整理一下两个工具的作用。

工具 目的
jdeps 调查 jar / class 所依赖的类和模块
jdeprscan 检测 Deprecated / Removed API 的使用位置

作业流程如下:

  1. 首先使用 jdeps 掌握依赖关系,补全 classpath
  2. 然后使用 jdeprscan 检测 JDK17 不兼容的 API

3. 确定依赖关系(构建 classpath)

在使用 jdepsjdeprscan 时,如果无法解析依赖的类,会出现以下错误:

class … not found

由于本项目不使用 Maven,因此不存在 pom.xml 或 dependency tree 这样的依赖管理。

在本项目中,最初的 classpath 设定仅使用了服务启动时 .bat 文件中所记载的内容(从日志中获取)。然而在扫描第一个 jar 文件时,便出现了上述错误。

原因在于,日志中记载的 classpath 仅包含 EAR 文件启动所需的依赖,而当前扫描对象是 jar 文件,因此需要的是 jar 文件构建时所使用的依赖。

为此,查阅了 Ant 的 build.xml,将 jar 构建时所使用的依赖补充到了 classpath 中。

即便如此,在后续扫描中该错误再次出现。借助 jdeps 的输出信息与 AI 辅助,找到了最后一块拼图——散布在各个 WAR 包中的 lib 目录。这说明,同一 EAR 包内的各模块之间存在依赖关系。

将各 WAR 的 lib 也加入 classpath 后,class not found 的错误得以彻底解决。

然而,另一个问题随之出现。

扫描结果中出现了「エラー: Methodref ……を解決できません」。

原因是 classpath 中存在同名但版本不同的 jar 包。由于 classpath 按从左到右的顺序进行类的检索,旧版 jar 被优先引用。而应用程序实际运行时使用的是新版 jar——新版相较旧版新增了方法的重载(オーバーロード)。因此,jdeprscan 参照旧版 jar 进行扫描时,该重载方法不存在,从而导致了解析失败。

Ant 项目的注意事项:
Ant 项目中不存在 Maven 的 dependency tree,因此还原 classpath 是最大的工作量。

本次案例中,通过整合以下内容构建了可供扫描的 classpath:

  • 启动脚本中的 classpath
  • 项目内 lib 目录
  • EAR 展开结果的 jar
  • 各 WAR 内的 lib

实行命令示例:

set "cp=lib\*;modules\*;thirdparty\*"
set "JAR=扫描对象的绝对路径"
set "OUT=日志输出目标的绝对路径"

:: 依赖调查
"%JAVA_17_HOME%\bin\jdeps.exe" --class-path "%cp%" "%JAR%" > "%OUT%" 2>&1

4. API 扫描(jdeprscan)

classpath 构建完成后,执行 jdeprscan

set "cp=lib\*;modules\*;thirdparty\*"
set "JAR=扫描对象的绝对路径"
set "OUT=日志输出目标的绝对路径"

:: 执行扫描(必须指定 --class-path 和 --release)
"%JAVA_17_HOME%\bin\jdeprscan.exe" --class-path "%cp%" --release 17 "%JAR%" > "%OUT%" 2>&1

注意:
省略 --class-path 选项,辛苦构建的 classpath 将完全不被使用,请务必明确指定。

同时,明确指定 --release 17,可以从命令中一目了然地看出正在与 JDK17 的废弃 API 列表进行对照,也能防止在其他环境复用时发生误操作。

通过将日志输出到文件,可以在之后随时确认。

扫描结果示例

class com/example/app/LegacyUtil uses deprecated method java/lang/Thread::stop()V
class com/example/app/DataHelper uses deprecated method java/util/Date::<init>(III)V
class com/example/app/XmlParser uses deprecated class com/sun/org/apache/xml/internal/utils/URI

注意: 输出中包含 forRemoval=true 的项目,是预计在未来版本中被删除的 API,请优先处理。

本次幸运的是,仅存在:

  • 对旧 API 的引用
  • 部分 deprecated API

因此不需要大规模的依赖更新或代码修改。


5. 应对大量代码修改

JDK 迁移还有另一个课题,那就是大量的代码修改。

确认 jdeprscan 的结果后,会在多处检测到 Deprecated API / Removed API。

由于手动修改这些内容非常耗时,目前正在开发一款使用 PowerShell v5.1 的辅助工具。

工具的使用流程如下:

  1. 解析扫描结果
  2. 提取修改候选
  3. 将 Evidence 输出到 CSV
  4. 人工审查
  5. 仅自动应用已批准的修改

也就是说,采用 AI + 自动化 + 人工审查 的形式。

关于该工具的详细内容,将在另一篇文章中介绍。


总结

对于 Ant + WebLogic 这样的遗留 Java EE 系统,JDK 迁移的第一道门槛就是掌握依赖关系。

本次调查采取了以下步骤:

  1. 展开 EAR,整理扫描对象
  2. 从启动脚本、build.xml、EAR 展开结果、各 WAR 的 lib 构建 classpath
  3. 使用 jdeps --class-path 调查、补全依赖关系
  4. 使用 jdeprscan --class-path --release 17 检测 API 不兼容性

对于不使用 Maven 的系统,正确构建 classpath 以及必须明确指定 --class-path 是非常重要的。

目前正在开发使用 PowerShell 的辅助工具,关于该工具也将在另一篇文章中介绍。


本文转载自作者的 Zenn 主页:https://zenn.dev/lockie2022

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐