基于JDK17及以上版本,制作内置JRE的可执行应用。
一、使用jdeps
与jmod
寻找模块依赖
jdeps \
--print-module-deps \
--ignore-missing-deps \
-recursive \
target/app.jar
jdeps
无法统计部分依赖,如:非模块化的依赖、动态加载或反射的依赖等等。可以使用下述jmod
脚本手工找到对应的依赖:
JAVA_HOME=/usr/lib/jvm/java-21-openjdk
CLASS=javax.management.NotificationEmitter
find $JAVA_HOME/jmods -name "*.jmod" -exec sh -c "jmod list {} | grep -q $CLASS && echo {}" \;
二、使用jlink
生成自定义JRE
JAVA_HOME=/usr/lib/jvm/java-21-openjdk
MOUDLES=java.base # 填入上述统计的模块依赖
jlink \
--output jre \
--module-path $JAVA_HOME/jmods \
--add-modules $MOUDLES \
--strip-debug \
--no-header-files \
--no-man-pages
--output
:指定输出目录--module-path
:指定模块路径--add-modules
:指定要包含的模块,可使用$(java --list-modules | cut -d "@" -f 1 | tr "\n" ",")
获取所有jmod--strip-debug
:移除调试信息,大幅缩减JRE体积--no-header-files
/--no-man-pages
:移除include中的c++头文件和man中的帮助文档文件
可使用jimage
查看目标JRE中的所有class:
jimage list jre/lib/modules
三、使用jpackage
打包应用
jpackage \
--input target \
--main-jar app.jar \
--type app-image \
--name app \
--dest output \
--runtime-image jre
--input
:指定包含应用程序文件的输入目录,jpackage会从这个目录中查找要打包的文件--main-jar
:指定主JAR文件,如果JAR的MANIFEST.MF
已指定Main-Class
,可省略--main-class
参数,如:SpringBoot打包后的FatJar。--type
:指定安装包类型,可选值:app-image、deb、rpm、exe、msi、pkg--name
:指定应用程序名称。不显性指定时,默认为Main-Class对应的值--dest
:指定输出目录。不显性指定时,默认为当前目录--runtime-image
:指定自定义的JRE运行时。不显性指定时,默认使用未经过裁剪的JRE