一、背景
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 模块化应用走向云原生、自包含、轻量运行时的关键工具。