Java 21 或 JavaFX 打包 exe 之 GraalVM Native Image 方案
JavaFX 打包 exe 的方法有很多,总结起来,大概可分为 3 种方案
方案一:Java 运行时 + exe 启动器
该方案的通用性很好,但是有一个缺点是生成的包很大,因为它整个JDK环境放进包里了,比如 jdk21 解压后的大小就是300M,再加上项目文件和各种依赖,就会更大。
实现步骤,以 jpakage 为例:
步骤1:打包成 Fat Jar
首先把项目打包成一个可运行Fat Jar,在这jar中包含了所有依赖和main入口
Spring Boot Maven 插件可以参考:Spring Boot Maven Plugin
我这里使用的是Gradle 的 shadow 插件,配置如下
plugins {id("java")id("com.gradleup.shadow") version "9.2.2"
}
执行插件
.\gradlew clean shadowJar
结果将生成文件:D:\projiects\summary\build\libs\summary-1.0-all.jar
文件大小为 9M,因为功能仅仅只是创建一个窗口,显示一行文字
执行命令java -jar summary-1.0-all.jar
可直接运行 jar 包,如图
步骤2:打包成 app-image
jpackage --type app-image -n App --input .\build\libs\ --main-jar summary-1.0-all.jar --dest .\build\ --icon logo.ico
打包镜像成功后,App 镜像中包括了Java21的运行时 runtime,和可执行程序 App.exe。大小总共有 206M,如图
步骤3:打包为安装程序
需要先安装wix314.exe,然后再执行步骤2的命令,去掉其中参数 --type app-image
jpackage -n App --input .\build\libs\ --main-jar summary-1.0-all.jar --dest .\build\ --icon logo.ico
其实真没有必要打安装包,不如直接打个 7z 格式的压缩包,大小只有 52M
方案二:采用Java模块化开发
Java 模块化项目与非模块化的项目区别就是多了一个 module-info.java 文件,里面有依赖声明 require 和访问权限声明 export 与 open。
使用 jlink 可以创建一个最小化 Java 运行时镜像 runtime-image。
使用 jpackage 可以基于这个定制的 runtime-image(而非完整的JDK)打包。
这样打包如JDK21,解压之后的大小有100M,比方案一的200M小了很多。
但是有些依赖并非模块的jar包,Java 就引入了 未命名模块 和 自动模块 2个概念来兼容非模块化依赖,但是也可能出现无法兼容的问题,就需手动修改jar包了。
把非模块化jar修改成模块化jar,即:添加module-info,步骤如下:
- 使用 jdeps 分析jar包的依赖项
- 根据自己的理解创建 module-info.java
- 使用 javac 命令把 module-info.java 编译成 module-info.class
- 使用 jar 命令把 module-info.class 添加到你所修改的 jar 文件中去
这一看就是一件很繁琐的事情,需要你对该 jar 包有一定了解,所以该方案 的通用性并不好。
下面我们通过 gradle 插件来执行 jlink 与 jpackage
步骤1:配置插件
plugins {id("org.beryx.jlink") version "3.1.4-rc"
}
jlink {forceMerge("log4j-api")options.set(listOf("--strip-debug", "--no-header-files", "--no-man-pages"))launcher {name = "summary"jvmArgs = listOf("--add-op