一、背景
JDK 9 引入了 模块系统(JPMS) ,把庞大的 JDK 拆成了上百个模块。
这样我们就可以:
-
只引入应用需要的模块;
-
用
jlink
工具生成一个定制化 runtime 镜像; -
从"依赖系统 JRE" 到 "自带专属 JRE"。
总结:
它是 Maven 对 JDK 自带工具
jlink
的封装,让模块化构建、镜像生成、依赖分析自动化。
二、原理:它到底做了什么
从执行流程看,它本质上完成这三件事:
(1)分析模块依赖树
它会解析:
-
你的
module-info.java
; -
依赖的模块(无论是 JDK 模块还是第三方模块);
-
并根据 Maven 依赖生成一棵 模块依赖树。
例如:
com.example.app
├─ java.base
├─ java.sql
└─ org.apache.logging.log4j
(2)调用 jlink 进行镜像生成
maven-jlink-plugin
会在目标目录下执行等价于:
jlink \
--module-path target/classes:target/dependency \
--add-modules com.example.app \
--launcher app=com.example.app/com.example.app.Main \
--output target/runtime \
--strip-debug \
--compress=2 \
--no-header-files \
--no-man-pages
结果是:
target/runtime/ ├─ bin/app ├─ conf/ ├─ lib/ └─ release
这个 runtime 就是一个独立可执行的、定制 JRE 镜像。
(3)支持与 jpackage 链接
maven-jlink-plugin
生成的 runtime 可直接喂给 maven-jpackage-plugin
,后者能打成 .exe
、.deb
、.pkg
安装包或 Docker 基镜像。
三、核心配置详解
下面是官方参数的"全家桶级别"解释。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jlink-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<goals>
<goal>jlink</goal>
</goals>
</execution>
</executions>
<configuration>
<output>${project.build.directory}/runtime</output>
<modulePaths>
<modulePath>${project.build.outputDirectory}</modulePath>
<modulePath>${project.build.directory}/dependency</modulePath>
</modulePaths>
<addModules>
<addModule>com.example.app</addModule>
</addModules>
<launcher>app=com.example.app/com.example.app.Main</launcher>
<stripDebug>true</stripDebug>
<compress>2</compress>
<noHeaderFiles>true</noHeaderFiles>
<noManPages>true</noManPages>
<jlinkExecutable>${java.home}/bin/jlink</jlinkExecutable>
</configuration>
</plugin>
主要参数说明:
参数名 | 说明 |
---|---|
output |
输出路径。生成的 runtime 镜像目录。 |
modulePaths |
jlink 搜索模块的路径。通常包括:编译输出 + 依赖目录。 |
addModules |
指定要加入镜像的模块(可以是 app 模块 + JDK 模块)。 |
launcher |
创建一个启动器脚本:别名=模块名/主类 。 |
stripDebug |
去除 .class 中的调试信息,减小体积。 |
compress |
压缩级别(0 无压缩、1 常规、2 最大压缩)。 |
noHeaderFiles |
移除头文件(减少体积)。 |
noManPages |
移除 man 手册页(减少体积)。 |
jlinkExecutable |
指定 jlink 可执行文件路径,通常不需改。 |
四、生命周期集成
maven-jlink-plugin
通常绑定在 package
阶段之后执行。
常见执行链:
mvn clean package jlink:jlink
如果要自动化,可以配置到 lifecycle:
<execution>
<id>create-runtime</id>
<phase>package</phase>
<goals><goal>jlink</goal></goals>
</execution>
五、典型优化组合
构建极小运行时镜像(常用于容器):
<configuration>
<stripDebug>true</stripDebug>
<compress>2</compress>
<noHeaderFiles>true</noHeaderFiles>
<noManPages>true</noManPages>
<ignoreSigningInformation>true</ignoreSigningInformation>
<stripNativeCommands>true</stripNativeCommands>
<verbose>true</verbose>
</configuration>
这种配置生成的 runtime 通常只有 30--60MB,且完全自包含。
六、Docker 示例
FROM scratch
COPY target/runtime /opt/runtime
WORKDIR /opt/runtime
ENTRYPOINT ["./bin/app"]
这是真正意义上的 零依赖 Java 容器 ,比传统 openjdk:17-jdk-slim
小几十 MB。
七、注意事项
-
必须是模块化项目
需要
module-info.java
,否则无法分析模块依赖。 -
第三方库未模块化
对未显式声明模块的 jar,jlink 会自动生成 automatic module,但可能导致命名冲突。
-
jlink 只适用于 Java 9+
若你使用 JDK 8 或更早版本,无法使用。
-
多平台兼容性
runtime 镜像与构建平台绑定,例如在 macOS 构建的 runtime 无法在 Linux 运行。
八、实践建议
-
在 CI/CD 流程中,把
maven-jlink-plugin
放到独立 stage,生成 runtime 后缓存; -
对 Spring Boot 3+ 模块化项目,建议结合
spring-boot-jarmode-tools
; -
若要发布安装包,直接串联
maven-jpackage-plugin
。
九、总结
maven-jlink-plugin
= Maven 模块化构建 + jlink Runtime 构建自动化它是 Java 模块化应用走向云原生、自包含、轻量运行时的关键工具。