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

相关推荐
lifallen3 小时前
从Apache Doris 学习 HyperLogLog
java·大数据·数据仓库·算法·apache
Knight_AL3 小时前
Java 单元测试全攻略:JUnit 生命周期、覆盖率提升、自动化框架与 Mock 技术
java·junit·单元测试
cominglately3 小时前
记录一次生产环境数据库死锁的处理过程
java·死锁
用户0332126663673 小时前
在 Word 文档中插入图片的 Java 指南
java
深圳蔓延科技3 小时前
单点登录到底是什么?
java·后端
SimonKing3 小时前
除了 ${},Thymeleaf 的这些用法让你直呼内行
java·后端·程序员
科兴第一吴彦祖4 小时前
基于Spring Boot + Vue 3的乡村振兴综合服务平台
java·vue.js·人工智能·spring boot·推荐算法
ajassi20004 小时前
开源 java android app 开发(十八)最新编译器Android Studio 2025.1.3.7
android·java·开源
纤瘦的鲸鱼4 小时前
Spring Gateway 全面解析:从入门到进阶实践
java·spring·gateway