找到丢失的模块

Find the missing module

我的问题:在构建最小的 JRE 时,如何确保没有缺少所需的模块?


为了说明这个问题,这里有一个例子,我想为我的项目构建一个最小的 JRE。对于这个例子,我们假设 logback 是我唯一的依赖。

我运行下面命令看看需要什么模块:

$ jar --file=logback-core-1.2.3.jar --describe-module
No module descriptor found. Derived automatic module.

logback.core@1.2.3 automatic
requires java.base mandated
contains ch.qos.logback.core
contains ch.qos.logback.core.boolex
etc. (there are more "contains ch.qos.logback.XXX" lines)

看起来我只需要 java.base 模块,我相应地构建了我的最小 JRE:

jlink --output jre-min --add-modules java.base

然而,当 运行使用最小的 JRE 连接项目时,我在使用 logback 的电子邮件记录器(通过 TLS 的格式错误的电子邮件)时遇到问题。通过反复试验,我发现 jdk.crypto.cryptoki 模块也是必需的:

jlink --output jre-min --add-modules java.base,jdk.crypto.cryptoki

现在我的项目工作正常。我怎样才能避免试错步骤?

您在那里使用的 JAR 文件“没有模块描述符”(请参阅​​输出的第一行),因此无法告诉您它依赖于哪些模块,因此您必须自己找出答案。规范的工具是 jdeps 但它可能还不够。

静态依赖

我写了a jdeps tutorial that gets you started, but the interesting bit is this section。要点是这个命令:

jdeps --class-path 'jars/*' -summary -recursive logback-core-1.2.3.jar

其中 jars 包含所有 Logback 依赖项。 (如果你手边没有这些,你可以将 --class-path-recursive 留在外面,但是你不知道依赖哪些模块。)除了一些其他的东西,输出将列出JDK 模块的依赖关系。

动态依赖

jdeps 通过分析字节码来工作,这意味着它只会找到静态链接的依赖项。因此,如果 JAR 使用反射、the service loader 或其他机制来避免明确提及它想要使用的 类,jdeps 将不会注意到它们。

要查找这些情况,您可以 运行 带有 java 命令行选项 -XX:DumpLoadedClassList=classes.lst 的应用程序 - 它会生成一个文件 classes.lst,其中列出了所有已加载的类.

最小运行时间

请注意,基本模块 java.base 使用了其他模块提供的许多服务,例如 [=57 提供的区域设置数据=]。这意味着最短的 运行 时间(即不包括服务提供者模块的时间)可能会错过应用程序需要的东西(在示例中,可能是语言环境)。

您可以使用 java --describe-module java.base 列出服务(请参阅输出中的 uses ... 列表),然后使用 jlink--suggest-providers 选项为每个服务找到潜在的提供者。

您可以使用 jlink--bind-services 选项包括所有可能的提供者,但这会立即放弃“最小”运行时间的想法,因为它将包括很多的模块。如果您想要“最小”,最好根据需要将它们一一包含。

无论您做什么,请确保在定制的 运行 时间内彻底测试您的应用。