1. 概述

jlink 是一个用于生成自定义 Java 运行时镜像的工具,该镜像仅包含运行特定应用程序所需的平台模块。

这种运行时镜像的行为与标准 JRE 相似,但它只包含我们指定的模块及其依赖项。模块化运行时镜像的概念由 JEP 220 引入。

本教程将介绍如何使用 jlink 创建一个自定义 JRE,并验证我们的模块是否能在该环境中正常运行。

2. 为什么要创建自定义 JRE

通过一个简单的例子来理解自定义运行时镜像的意义。

我们创建一个简单的模块化应用。如果对 Java 模块系统还不熟悉,可以先参考 Java 模块化相关文章

首先,我们创建一个 HelloWorld 类和对应的模块定义:

public class HelloWorld {
    private static final Logger LOG = Logger.getLogger(HelloWorld.class.getName());
    public static void main(String[] args) {
        LOG.info("Hello World!");
    }
}
module jlinkModule {
    requires java.logging;
}

要运行这个程序,理论上只需要 HelloWorldStringLoggerObject 类。

然而,即使程序只需要这几个类,标准 JRE 依然会加载所有预定义的类库——哪怕它们根本没被用到。

这就导致了一个问题:为了运行一个小程序,却不得不维护一个完整的 JRE,这明显是内存浪费。

因此,使用 jlink 来构建一个轻量化的、只包含必要模块的自定义 JRE 是最优解。

使用 jlink 可以创建一个精简的 JRE,只包含实际使用的模块和依赖,节省内存并提升性能。

3. 构建自定义 Java 运行时镜像

下面是创建自定义 JRE 的几个关键步骤。

3.1. 编译模块

首先,从命令行编译上面提到的模块代码:

javac -d out module-info.java
javac -d out --module-path out com\baeldung\jlink\HelloWorld.java

然后运行程序:

java --module-path out --module jlinkModule/com.baeldung.jlink.HelloWorld

输出如下:

Mar 13, 2019 10:15:40 AM com.baeldung.jlink.HelloWorld main
INFO: Hello World!

3.2. 使用 jdeps 查看依赖模块

在使用 jlink 前,我们需要知道应用程序使用了哪些 JDK 模块,以便将其包含进自定义 JRE。

使用 jdeps 工具查看模块依赖:

jdeps --module-path out -s --module jlinkModule

输出结果为:

jlinkModule -> java.base
jlinkModule -> java.logging

这符合预期,因为 java.base 是所有 Java 程序的基础模块,而 java.logging 是我们在程序中使用日志功能所依赖的模块。

要为基于模块的应用程序创建自定义 JRE,可以使用如下 jlink 命令语法:

jlink [options] –module-path modulepath
  –add-modules module [, module…]
  --output <target-directory>

现在,使用 Java 11 来为我们的程序创建自定义 JRE:

jlink --module-path "%JAVA_HOME%\jmods";out
  --add-modules jlinkModule
  --output customjre

📌 参数说明:

  • --add-modules:指定要包含在自定义 JRE 中的模块。
  • --output:指定自定义 JRE 的输出目录。

⚠️ 注意:本文所有命令均基于 Windows Shell 编写,Linux 或 Mac 用户可能需要调整路径分隔符等细节。

3.4. 使用生成的镜像运行程序

现在我们已经生成了自定义 JRE,可以进入 customjre/bin 目录并执行以下命令来运行程序:

java --module jlinkModule/com.baeldung.jlink.HelloWorld

📌 提示:在 Windows 中,系统会优先查找当前目录下的可执行文件;而在 Linux 或 Mac 中,需确保执行的是自定义 JRE 下的 java,而不是 PATH 中的默认版本。

4. 使用启动脚本创建自定义 JRE

我们还可以选择创建带有启动脚本(launcher)的自定义 JRE。

为此,只需在 jlink 命令中添加 --launcher 参数,指定模块和主类:

jlink --launcher customjrelauncher=jlinkModule/com.baeldung.jlink.HelloWorld
  --module-path "%JAVA_HOME%\jmods";out
  --add-modules jlinkModule
  --output customjre

执行后,会在 customjre/bin 目录下生成两个启动脚本:

  • customjrelauncher.bat(Windows)
  • customjrelauncher(Linux / Mac)

运行脚本:

customjrelauncher.bat

输出如下:

Mar 18, 2019 12:34:21 AM com.baeldung.jlink.HelloWorld main
INFO: Hello World!

5. 总结

通过本教程,我们学会了如何使用 jlink 创建一个只包含必要模块的自定义、模块化 JRE。我们也演示了如何使用启动脚本来简化部署和执行。

✅ 自定义模块化 Java 运行时镜像具有如下优势:

  • ✅ 节省内存
  • ✅ 提升性能
  • ✅ 增强安全性与可维护性
  • ✅ 适合部署在资源受限的小型设备上

本教程中的代码示例可在 GitHub 仓库 获取。


原始标题:Guide to jlink