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

相关推荐
惜缘破军5 分钟前
基于 Spring Boot 4 和 Spring Cloud 2025 的微服务基础框架 hdfk7-boot
java
小白起 v11 分钟前
从零搭建一个现代化的验证码登录系统:Spring Boot + 阿里云短信实战教程
java·阿里云
未若君雅裁20 分钟前
工厂模式详解:简单工厂、工厂方法与抽象工厂
java·开发语言
不会写DN24 分钟前
通过php 中的Route:: 的写法了解什么是静态类调用
android·java·php
小刘|24 分钟前
SpringAIAlibaba快速接入阿里云百炼
java·spring boot·spring·maven
我命由我1234528 分钟前
由 ImageView 获取到的 Drawable 对象,它的 intrinsicWidth、intrinsicWidth 与实际图片的尺寸
java·开发语言·java-ee·android studio·android jetpack·android-studio·android runtime
Han.miracle30 分钟前
Jackson 工具类详解:ObjectMapper 配置、泛型擦除、TypeReference 与 JavaType
java·spring boot·spring
guslegend31 分钟前
Java 创建对象有几种方式
java·开发语言
暗暗别做白日梦32 分钟前
延时消息的几种实现方式及优缺点
java
极客先躯35 分钟前
高级java每日一道面试题-2026年02月08日-实战篇[Docker]-如何实现容器的快照和恢复?
java·运维·docker·容器·备份·持久化·恢复