maven-jlink-plugin入门

一、背景

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

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。


七、注意事项

  1. 必须是模块化项目

    需要 module-info.java,否则无法分析模块依赖。

  2. 第三方库未模块化

    对未显式声明模块的 jar,jlink 会自动生成 automatic module,但可能导致命名冲突。

  3. jlink 只适用于 Java 9+

    若你使用 JDK 8 或更早版本,无法使用。

  4. 多平台兼容性

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

相关推荐
程序员清风1 小时前
程序员兼职必看:靠谱软件外包平台挑选指南与避坑清单!
java·后端·面试
皮皮林5513 小时前
利用闲置 Mac 从零部署 OpenClaw 教程 !
java
华仔啊8 小时前
挖到了 1 个 Java 小特性:var,用完就回不去了
java·后端
SimonKing8 小时前
SpringBoot整合秘笈:让Mybatis用上Calcite,实现统一SQL查询
java·后端·程序员
日月云棠1 天前
各版本JDK对比:JDK 25 特性详解
java
用户8307196840821 天前
Spring Boot 项目中日期处理的最佳实践
java·spring boot
JavaGuide1 天前
Claude Opus 4.6 真的用不起了!我换成了国产 M2.5,实测真香!!
java·spring·ai·claude code
IT探险家1 天前
Java 基本数据类型:8 种原始类型 + 数组 + 6 个新手必踩的坑
java
花花无缺1 天前
搞懂new 关键字(构造函数)和 .builder() 模式(建造者模式)创建对象
java
用户908324602731 天前
Spring Boot + MyBatis-Plus 多租户实战:从数据隔离到权限控制的完整方案
java·后端