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;
}
要运行这个程序,理论上只需要 HelloWorld
、String
、Logger
和 Object
类。
然而,即使程序只需要这几个类,标准 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
是我们在程序中使用日志功能所依赖的模块。
3.3. 使用 jlink
创建自定义 JRE
要为基于模块的应用程序创建自定义 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 仓库 获取。