news 2026/4/18 6:27:09

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/4/18 2:05:30

YOLOv8 GhostNet极轻量替代选项探索

YOLOv8 GhostNet极轻量替代选项探索 在智能安防摄像头、工业巡检终端和消费级无人机等边缘设备上部署目标检测模型&#xff0c;常常面临一个尴尬的现实&#xff1a;算法精度达标了&#xff0c;但推理速度却卡在个位数帧率&#xff1b;模型结构优化了&#xff0c;可一跑torchsum…

作者头像 李华
网站建设 2026/4/18 2:07:26

YOLOv8雾天、雨天等恶劣天气适应性测试

YOLOv8在雾天、雨天等恶劣天气下的适应性实测与工程实践 在智能交通系统&#xff08;ITS&#xff09;和自动驾驶技术飞速发展的今天&#xff0c;视觉感知的鲁棒性已成为决定系统能否真正落地的关键瓶颈。摄像头作为最直观的传感器&#xff0c;其采集的数据极易受到雾、雨、低光…

作者头像 李华
网站建设 2026/4/18 2:06:24

青少年近视怎么预防?家长必知的核心要点你了解吗?

当下青少年近视发生率逐年攀升&#xff0c;已然成为困扰众多家庭的健康难题&#xff0c;不少家长重视孩子视力保护&#xff0c;却因缺乏专业认知&#xff0c;陷入防控误区&#xff0c;导致预防效果不尽如人意。青少年视力发育尚未成熟&#xff0c;眼部调节系统仍在完善&#xf…

作者头像 李华
网站建设 2026/4/18 2:05:22

从新手到专家:R语言GPT辅助调试的8个进阶步骤

第一章&#xff1a;R语言GPT辅助调试的认知革命传统R语言调试依赖于断点设置、逐行执行与错误日志分析&#xff0c;开发者常陷入“试错循环”。随着生成式AI的兴起&#xff0c;GPT类工具正重塑调试范式&#xff0c;将被动排查转化为主动推理与语义理解的协同过程。这一转变不仅…

作者头像 李华
网站建设 2026/4/18 3:52:57

企业级数据分析架构揭秘:为什么头部公司都在用Dify+Amplitude组合?

第一章&#xff1a;企业级数据分析的现状与挑战在当今数字化转型加速的背景下&#xff0c;企业级数据分析已成为驱动决策、优化运营和提升竞争力的核心手段。然而&#xff0c;随着数据规模的爆炸式增长和业务场景的日益复杂&#xff0c;企业在构建和维护数据分析体系时面临诸多…

作者头像 李华
网站建设 2026/4/18 3:52:35

YOLOv8 STAC半监督检测pipeline重构

YOLOv8 STAC半监督检测Pipeline重构&#xff1a;从算法融合到工程落地 在智能视觉系统日益普及的今天&#xff0c;一个现实问题始终困扰着工业界——标注数据的成本太高了。尤其在电力巡检、农业病虫害识别这类长尾场景中&#xff0c;每一张图像都需要专家反复确认边界框和类别…

作者头像 李华