news 2026/6/24 9:53:36

JavaFX Java 模块化 jpackage 打包 exe (手动 jlink 实战 + Gradle插件)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaFX Java 模块化 jpackage 打包 exe (手动 jlink 实战 + Gradle插件)

JavaFX Java 模块化 jpackage 打包 exe (手动 jlink 实战 + Gradle插件)


方案一:Java 运行时 + exe 启动器

该方案的通用性很好,但是有一个缺点是生成的包很大,因为它整个JDK环境放进包里了,比如 jdk21 解压后的大小就是300M,再加上项目文件和各种依赖,就会更大。
实现步骤,以 jpakage 为例:

步骤1:打包成 Fat Jar

首先把项目打包成一个可运行Fat Jar,在这jar中包含了所有依赖和启动入口类
Spring Boot Maven 插件可以参考:Spring Boot Maven Plugin
我这里使用的是Gradle 的 shadow 插件,配置如下

plugins{id("java")id("com.gradleup.shadow")version"9.2.2"}

执行插件

.\gradlew clean shadowJar

结果将生成文件:build\libs\summary-1.3-all.jar
文件大小为 28.4 MB
执行命令java -jar summary-1.0-all.jar可直接运行 jar 包,如图

步骤2:打包成 app-image

jpackage `--typeapp-image `--name App `--input.\build\libs\ `--main-jar summary-1.3-all.jar `--icon src/main/resources/excel.ico `--dest.\build\

打包镜像成功后, App 镜像中包括了Java21的运行时 runtime,和可执行程序 App.exe。大小总共有 225 MB,如图

步骤3:打包为安装程序

需要先安装wix314.exe,然后再执行步骤2的命令,去掉其中参数 --type app-image, 采用默认方式即可

jpackage-n App `--input.\build\libs\ `--main-jar summary-1.3-all.jar `--icon src/main/resources/excel.ico `--dest.\build\

安装包的文件大小为: 100M

方案二:模块化构建 Java 运行时

基础知识:
  • module-info.java 文件中, 依赖声明: require, 权限声明: export , open
  • 3个重要工具: jdeps , jlink , jpackage
  • 启动非模块化 java 应用:java -cp "依赖jar路径" com.taj.summary.Launcher
  • 启动模块化 java 应用:java -cp "非模块化jar路径" -p "模块化jar路径" -m 模块名/主函数所在的类名
  • -cp 路径的jar转为未命名模块, 如果把 非模块化jar放入 -p 路径下, 将转为自动模块
  • 未命名模块的依赖权限处理: export 所有包, require 所有模块
  • 自动模块的依赖权限处理: export 所有包, require 所有命名模块, 并且允许访问未命名模块
  • 需要被反射访问的包, 必须开启 open, 也可以在启动命令中对任意模块开启 open

1. 拷贝依赖

build.gradle.kts 配置

// 新增任务: copyDepstasks.register<Copy>("copyDeps"){// 复制运行时依赖到deps目录from(configurations.runtimeClasspath)into(layout.buildDirectory.dir("deps"))}// build 时执行任务 copyDepstasks.named("build"){dependsOn("copyDeps")}

也可以手动执任务 copyDeps

.\gradlew copyDeps

2. 使用 jdeps 分析依赖

输出 依赖模块
# 输出依赖模块: print-module-depsjdeps `--multi-release 21 `--ignore-missing-deps `--print-module-deps `--module-path".\build\deps\;$env:JAVAFX_HOME\jmods"`.\build\libs\summary-1.3.jar# 运行结果:java.base,javafx.controls,javafx.fxml,org.apache.commons.io,org.apache.logging.log4j,org.apache.poi.ooxml,org.kordamp.bootstrapfx.core

如果.\build\deps\中存在非模块化jar, jdeps 无法分析其依赖, 并自动忽略, 所以运行结果 一定是少于或等于实际依赖的

输出 依赖详情
# 输出依赖详情: -v (具体到每个类)jdeps-v `--multi-release 21 `--ignore-missing-deps `--module-path".\build\deps\;$env:JAVAFX_HOME\jmods"`.\build\libs\summary-1.3.jar
结论

根据分析, 得出对 java 和 javafx 的依赖只有3个模块:
java.base,javafx.controls,javafx.fxml
其他第3方依赖, 我们可以不用构建到 java 运行时

3. 使用 jlink 构建 Java 运行时

方法1: 根据 jdeps 的分析结果, 构建 java 运行时

该方法一般用于非模块化项目, 模块化项目也能用(精准控制添加模块)

# 运行时只包括 java 和 javafx 的模块jlink `--module-path"$env:JAVAFX_HOME\jmods"`--add-modulesjava.base,javafx.controls,javafx.fxml `--output.\build\custom-jre
方法2: 从自己的项目模块, 构建 java 运行时

前提条件: 你的项目已经是模块化, 并且所有依赖也都模块化
如果存在非模块化依赖, 需要手动处理, 后面有提供处理脚本
当然, 该方法可以不用进行 jdeps 依赖分析

# add-modules 只添加自己的项目模块, jlink 会自动分析依赖jlink `--module-path".\build\deps\;$env:JAVAFX_HOME\jmods"`--add-modulescom.taj.summary `--output.\build\custom-jre
进一步压缩
jlink `--module-path"$env:JAVAFX_HOME\jmods"`--add-modulesjava.base,javafx.controls,javafx.fxml `--output.\build\custom-jre `--compress=zip-6 `# 启用 ZIP 压缩--strip-debug `# 移除调试信息--no-header-files `# 不包含 native 头文件--no-man-pages# 不包含 man 手册
构建结果

我使用的是微软 JDK 21, 构建出的自定义运行时有 55.7 MB

PSD:\projiects\summary> java-version openjdk version"21.0.9"2025-10-21 LTS OpenJDK Runtime Environment Microsoft-12574459(build 21.0.9+10-LTS)OpenJDK 64-Bit Server VM Microsoft-12574459(build 21.0.9+10-LTS,mixed mode,sharing)

4. 打包: 非模块化项目

# 1 清理, 打包 jar, 复制依赖到 deps.\gradlew clean jar copyDepscp.\build\libs\summary-1.3.jar.\build\deps\# 2 构建运行时 custom-jrejlink `--module-path"$env:JAVAFX_HOME\jmods"`--add-modulesjava.base,javafx.controls,javafx.fxml `--output.\build\custom-jre `--compress=zip-6 `--strip-debug `--no-header-files `--no-man-pages# 3 删除 javafx 依赖, 因为运行时 custom-jre 中已经包含rm.\build\deps\javafx*# 4 打包: 非模块化项目jpackage `--typeapp-image `--name MyApp `--runtime-image
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 8:33:06

YOLOv8 Instance Segmentation实例分割精度测试

YOLOv8 实例分割精度测试与工程实践 在自动驾驶感知系统中&#xff0c;不仅要识别出“画面中有几辆车”&#xff0c;更需要精确地知道“每辆车的轮廓在哪里”。这种对每个独立对象进行像素级边界的划分任务&#xff0c;正是实例分割&#xff08;Instance Segmentation&#xff…

作者头像 李华
网站建设 2026/6/19 14:21:54

YOLOv8 Noisy Student自训练半监督学习

YOLOv8结合Noisy Student的半监督目标检测实践 在工业质检、医疗影像分析等现实场景中&#xff0c;高质量标注数据的获取始终是一道难以逾越的成本门槛。一张电路板缺陷图可能需要专家花费半小时标注&#xff0c;而医院的CT序列动辄成千上万帧——这些领域普遍存在“数据丰富但…

作者头像 李华
网站建设 2026/6/22 13:39:36

不用打乱学习的近视防控技巧,你都清楚吗?

你是不是也发现&#xff0c;身边戴眼镜的孩子越来越多&#xff1f;尤其是课业压力渐增的阶段&#xff0c;想让孩子防控近视&#xff0c;又怕耽误学习进度——这大概是很多家长的共同困扰。其实&#xff0c;不用打乱学习节奏&#xff0c;也能做好近视防控&#xff0c;关键在于找…

作者头像 李华
网站建设 2026/6/15 20:57:36

低龄儿童近视可逆吗?这些防控期知识你清楚吗?

当下低龄儿童近视发生率逐年攀升&#xff0c;越来越多家长在孩子检出视力异常时&#xff0c;都会迫切追问同一个核心问题&#xff1a;低龄儿童近视可逆吗&#xff1f;关于低龄阶段近视防控的关键知识&#xff0c;不少家长仍存在认知盲区&#xff0c;若不能及时厘清核心逻辑&…

作者头像 李华
网站建设 2026/6/23 10:20:54

Redis语法入门

redis是“键值对”型的数据结构 核心数据结构 字符串&#xff1a;String&#xff08;文本、数值&#xff09; # 设置键 SET key value; # 获取键 GET key # 向键已存在的值追加内容 APPEND key value #计数器-自增-自减 INCR key DECR key # 将键增加、减少指定的值 INCRBY key…

作者头像 李华
网站建设 2026/6/22 18:52:06

罗氏线圈 Comsol 建模与电磁模拟仿真探索

罗氏线圈comsol建模&#xff0c;电磁模拟仿真最近在研究电磁领域相关内容&#xff0c;罗氏线圈的建模与仿真可太有趣了&#xff0c;今天就来跟大家分享下罗氏线圈在 Comsol 中的建模以及电磁模拟仿真过程。 罗氏线圈简介 罗氏线圈&#xff0c;又称空心线圈&#xff0c;它依据电…

作者头像 李华