jlink

返回 JDK 工具

jlink 是 JDK 9 引入的自定义运行时镜像生成工具,基于 Java 平台模块系统(JPMS),可将应用所依赖的模块裁剪打包为最小化 JRE,无需分发完整 JDK/JRE。


核心概念

概念说明
模块(module)JPMS 的基本单元,每个模块声明依赖与导出(module-info.java
jmods/$JAVA_HOME/jmods 下存放各平台标准模块的 .jmod 文件
运行时镜像jlink 输出的自包含目录,含 bin/java、裁剪后的库和资源

基本用法

# 生成只含 java.base 的最小运行时
jlink \
  --module-path $JAVA_HOME/jmods \
  --add-modules java.base \
  --output minimal-jre
 
# 生成含常用模块的运行时(适合 GUI/日志/网络应用)
jlink \
  --module-path $JAVA_HOME/jmods \
  --add-modules java.base,java.desktop,java.logging,java.net.http \
  --output custom-jre \
  --strip-debug \
  --compress=2 \
  --no-header-files \
  --no-man-pages

常用选项

选项说明
--module-path <path>模块查找路径,通常指向 $JAVA_HOME/jmods
--add-modules <modules>要包含的模块列表(逗号分隔),依赖会自动递归包含
--output <dir>输出目录(不能已存在)
--strip-debug去除调试符号,减小体积
--compress=<0|1|2>压缩级别:0 不压缩,1 字符串共享,2 ZIP 压缩
--no-header-files不包含头文件(.h),进一步缩减体积
--no-man-pages不包含 man 手册页
--launcher <name>=<module>/<class>bin/ 中生成启动脚本
--save-opts <file>将本次参数保存到文件供复用
--list-modules列出输出镜像中包含的所有模块

自动推断模块依赖

使用 jdeps 工具先分析 JAR 所依赖的模块,再传给 jlink:

# 1. 分析 app.jar 依赖的 JDK 模块
jdeps --print-module-deps app.jar
# 示例输出:java.base,java.logging,java.sql
 
# 2. 将输出直接传给 jlink
jlink \
  --module-path $JAVA_HOME/jmods \
  --add-modules $(jdeps --print-module-deps app.jar) \
  --output custom-jre \
  --strip-debug \
  --compress=2

添加启动器

--launcher 在输出镜像的 bin/ 目录中生成可直接运行的脚本:

jlink \
  --module-path $JAVA_HOME/jmods:mods \
  --add-modules com.example.app \
  --launcher myapp=com.example.app/com.example.Main \
  --output app-jre
 
# 运行
app-jre/bin/myapp

体积对比示例

内容大小(参考)
完整 JRE 21~300 MB
jlink(java.base 仅基础模块)~40 MB
jlink + strip-debug + compress=2~25 MB

实际大小因模块数量和 JDK 版本而异。


与 jpackage 配合

jlink 生成的裁剪运行时可直接交给 jpackage 打包为原生安装程序,大幅缩小分发体积:

# 1. 裁剪运行时
jlink \
  --module-path $JAVA_HOME/jmods \
  --add-modules java.base,java.desktop,java.logging \
  --output custom-jre \
  --strip-debug \
  --compress=2
 
# 2. 打包为原生安装程序
jpackage \
  --name MyApp \
  --runtime-image custom-jre \
  --input lib/ \
  --main-jar app.jar \
  --main-class com.example.Main

常见问题

Q: 运行时报 module not found 怎么办?
A: 使用 jdeps --print-module-deps 重新分析,确认所有依赖模块都已加入 --add-modules

Q: 第三方 JAR 没有 module-info.java 怎么处理?
A: 非模块化 JAR 需放在 --module-path 的 classpath 部分,或通过 --add-modules ALL-MODULE-PATH 强制包含。


相关链接

  • jpackage — 使用裁剪运行时打包原生安装程序
  • 编译与运行 — 从源码到 jar 的完整流程
  • javac — 模块化编译选项(--module-source-path
  • jcmd — 运行时模块信息查询(VM.system_properties