高版本jdk的模块化与自定义jre
1. 概述
*jlink* 是一种工具,用于生成自定义 Java 运行时映像,该映像仅包含给定应用程序所需的平台模块。
这样的运行时镜像与 JRE 完全相同,但仅包含我们选择的模块以及它们运行所需的依赖项。模块化运行时映像的概念是在 JEP 220 中引入的。
在本教程中,我们将学习如何使用 jlink 创建自定义 JRE,我们还将运行和测试我们的模块在 JRE 中是否正常运行。
2. 需要创建自定义 JRE
让我们通过一个示例来了解自定义运行时映像背后的动机。
我们将创建一个简单的模块化应用程序。
首先,让我们创建一个 HelloWorld 类和相应的模块:
mkdir java && cd java
创建 module-info.java
module moduleDemo {
requires java.logging;
}
创建包
mkdir -p com/bingbaihanji/jlink && cd com/bingbaihanji/jlink
创建 HelloWorld.java
package com.bingbaihanji.jlink;
import java.util.logging.Logger;
public class HelloWorld {
private static final Logger LOG = Logger.getLogger(HelloWorld.class.getName());
public static void main(String[] args) {
LOG.info("Hello World!");
}
}
项目结构如下
.
├── com
│ └── bingbaihanji
│ └── jlink
│ └── HelloWorld.java
└── module-info.java
要运行这个程序,我们只需要 *HelloWorld、*String、Logger 和 Object 类。
尽管这个程序只需要四个类来运行,但 JRE 中的所有预定义类也会被执行,即使我们的程序不需要它们。
所以,要运行一个小程序,就得维护一个完整的 JRE,简直就是浪费内存。
因此,自定义的 JRE 是运行示例的最佳选择。
使用 *jlink*,我们可以创建自己的小型 JRE,其中仅包含我们想要使用的相关类,而不会浪费内存,因此,我们将看到性能的提高。
3. 构建自定义 Java 运行时映像
我们将执行一系列简单的步骤来创建自定义 JRE 映像。
3.1. 编译模块
首先,让我们从命令行编译上面提到的程序:
编译 module-info.java
javac -d out module-info.java
编译 HelloWorld.java
javac -d out --module-path out com\bingbaihanji\jlink\HelloWorld.java
运行该项目:
java --module-path out --module moduleDemo/com.bingbaihanji.jlink.HelloWorld
输出结果
12月 15, 2024 3:08:23 下午 com.bingbaihanji.jlink.HelloWorld main
信息: Hello World!
3.2. 使用 jdeps 列出依赖模块
为了使用 jlink,我们需要知道应用程序使用的 JDK 模块列表,我们应该将其包含在自定义 JRE 中。
让我们使用 jdeps 命令来获取应用程序中使用的依赖模块:
jdeps --module-path out -s --module moduleDemo
结果
moduleDemo -> java.base
moduleDemo -> java.logging
这很合理,因为 java.base 是 Java 代码库所需的最小模块,而 java.logging 由我们程序中的 Logger 使用。
3.3. 使用 jlink 创建自定义 JRE
要为基于模块的应用程序创建自定义 JRE,我们可以使用 jlink 命令。以下是它的基本语法:
jlink --help
用法: jlink <选项> --module-path <模块路径> --add-modules <模块>[,<模块>...]
现在,让我们使用 Java 21 为我们的程序创建自定义 JRE:
bash:
jlink --module-path $JAVA_HOME/jmods:out \
--add-modules moduleDemo \
--output custom-jre
PowerShell:
jlink --module-path "$env:JAVA_HOME\jmods;out" `
--add-modules moduleDemo `
--output custom-jre
其中
--module-path
指定模块的搜索路径,jlink
会在这些路径中查找需要打包的模块。
模块路径可以包括:
- JDK 提供的标准模块文件(通常位于
$JAVA_HOME/jmods
)。 - 用户定义的模块(如你项目的
out
目录)
--add-modules
指定要打包的模块列表。
jlink
会从指定的模块开始,并自动分析模块依赖,将依赖的模块一起打包到自定义 JRE 中。
--add-modules moduleDemo
--output
指定生成的自定义 JRE 的输出目录。
示例:
plaintext
复制代码
--output custom-jre
custom-jre
是输出目录名,你可以随意命名。- 执行后,
custom-jre
目录下将包含自定义 JRE 的所有文件和结构,如bin
、lib
等。
完成后会在当前目录产生自定义项目的jre custom-jre
其他扩展选项
--compress
指定压缩级别以减少自定义 JRE 的大小:
--compress=0
:不压缩(默认)。--compress=1
:常量池字符串共享。--compress=2
:常量池字符串共享并进行 ZIP 压缩。
3.4. 使用生成的映像运行应用程序
.\custom-jre\bin\java.exe --module-path out --module moduleDemo/com.bingbaihanji.jlink.HelloWorld
结果:
Dec 15, 2024 3:23:40 PM com.bingbaihanji.jlink.HelloWorld main
信息: Hello World!
5. 总结
使用 jlink 创建自定义的模块化 JRE,该 JRE 仅包含模块所需的最少文件。
自定义的模块化 Java 运行时映像非常强大。创建自定义 JRE 的目标很明确:它们可以节省内存、提高性能,还可以增强安全性和可维护性。 轻量级自定义 JRE 还使我们能够为小型设备创建可扩展的应用程序。