jpackage的核心价值:创建独立可运行的java程序,java runtime 可裁剪从而减少体积,方便部署,方便容器化。
jpackage属于jdk的官方工具,具体用法见官方文档。
Step 0: 前提条件
- 系统安装JDK17+
- Windows下自制二进制程序必须安装Wix: WiX Toolset. wix3已验证,更高版本可能有问题。
Step1: maven配置: 配置关键的plugin
maven-dependency-plugin
拷贝依赖包,方便后面jdeps分析和jlink处理
exec-maven-plugin
执行外部脚本,传递变量
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/libs</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<includeScope>compile</includeScope>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<version>${exec.maven.plugin.version}</version>
<executions>
<execution>
<id>Build Native Windows App</id>
<phase>install</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<workingDirectory>${project.basedir}</workingDirectory>
<executable>build_app_windows.bat</executable>
<environmentVariables>
<MAIN_JAR_NAME>${project.artifactId}</MAIN_JAR_NAME>
<APP_VERSION>1.0</APP_VERSION>
<PROJECT_VERSION>${project.version}</PROJECT_VERSION>
<MAIN_CLASS>com.nubomed.mid.integration.NuboMedHL7ServerApp</MAIN_CLASS>
</environmentVariables>
</configuration>
</plugin>
Step2: jdeps + jlink + jpackage
参考脚本:https://github.com/HanSolo/JDKMon/blob/main/build_app_windows.bat
调整后的脚本如下(基于自己的需要微调。注意msi和exe类型的都是安装包,只有app-image是直接运行):
@ECHO OFF
rem ------ ENVIRONMENT --------------------------------------------------------
rem The script depends on various environment variables to exist in order to
rem run properly. The java version we want to use, the location of the java
rem binaries (java home), and the project version as defined inside the pom.xml
rem file, e.g. 1.0-SNAPSHOT.
rem
rem PROJECT_VERSION: version used in pom.xml, e.g. 1.0-SNAPSHOT
rem APP_VERSION: the application version, e.g. 1.0.0, shown in "about" dialog
set JAVA_VERSION=17
set MAIN_JAR=%MAIN_JAR_NAME%-%PROJECT_VERSION%.jar
set MAIN_CLASS_NAME=%MAIN_CLASS%
rem Set desired installer type: "app-image" "msi" "exe".
set INSTALLER_TYPE=app-image
rem ------ SETUP DIRECTORIES AND FILES ----------------------------------------
rem Remove previously generated java runtime and installers. Copy all required
rem jar files into the input/libs folder.
IF EXIST target\java-runtime rmdir /S /Q .\target\java-runtime
IF EXIST target\installer rmdir /S /Q target\installer
xcopy /S /Q target\libs\* target\installer\input\libs\
xcopy /S /Q target\conf\* target\installer\input\conf\
copy target\%MAIN_JAR% target\installer\input\libs\
rem ------ REQUIRED MODULES ---------------------------------------------------
rem Use jlink to detect all modules that are required to run the application.
rem Starting point for the jdep analysis is the set of jars being used by the
rem application.
echo detecting required modules
"%JAVA_HOME%\bin\jdeps" ^
-q ^
--multi-release %JAVA_VERSION% ^
--ignore-missing-deps ^
--class-path "target\installer\input\libs\*" ^
--print-module-deps target\%MAIN_JAR% > temp.txt
set /p detected_modules=<temp.txt
echo detected modules: %detected_modules%
rem ------ MANUAL MODULES -----------------------------------------------------
rem jdk.crypto.ec has to be added manually bound via --bind-services or
rem otherwise HTTPS does not work.
rem
rem See: https://bugs.openjdk.java.net/browse/JDK-8221674
rem
rem In addition we need jdk.localedata if the application is localized.
rem This can be reduced to the actually needed locales via a jlink parameter,
rem e.g., --include-locales=en,de.
rem
rem Don't forget the leading ','!
set manual_modules=,jdk.crypto.ec,jdk.localedata,java.naming,jdk.management
echo manual modules: %manual_modules%
rem ------ RUNTIME IMAGE ------------------------------------------------------
rem Use the jlink tool to create a runtime image for our application. We are
rem doing this in a separate step instead of letting jlink do the work as part
rem of the jpackage tool. This approach allows for finer configuration and also
rem works with dependencies that are not fully modularized, yet.
echo creating java runtime image
call "%JAVA_HOME%\bin\jlink" ^
--strip-native-commands ^
--no-header-files ^
--no-man-pages ^
--compress=2 ^
--strip-debug ^
--add-modules %detected_modules%%manual_modules% ^
--include-locales=en,de ^
--output target/java-runtime
rem ------ PACKAGING ----------------------------------------------------------
rem In the end we will find the package inside the target/installer directory.
call "%JAVA_HOME%\bin\jpackage" ^
--type %INSTALLER_TYPE% ^
--dest target/installer ^
--input target/installer/input ^
--name MySuperApp ^
--main-class %MAIN_CLASS_NAME% ^
--main-jar libs/%MAIN_JAR% ^
--java-options -Xmx502m ^
--java-options "-classpath $APPDIR\conf;$APPDIR\libs\*" ^
--runtime-image target/java-runtime ^
--icon src/main/logo/windows/app_icon.ico ^
--app-version %APP_VERSION% ^
--vendor "Super Inc." ^
--copyright "Copyright ? 2024 Super Inc." ^
--win-console
几个细节:
- 如何使用外部配置文件 (External Configuration) 方便修改:需要三个部分配置
bat文件中:
拷贝配置文件到中间目录:
xcopy /S /Q target\conf\* target\installer\input\conf\
修改jpackage参数定制classpath:注意$APPDIR
是jpackage标准的变量,必须verbatim传递给jpackage
--java-options "-classpath $APPDIR\conf;$APPDIR\libs\*" ^
maven 中配置maven-resource-plugin:
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
<outputDirectory>${project.build.directory}/conf/</outputDirectory>
<overwrite>true</overwrite> <!-- 覆盖前面自动拷贝的同名文件 -->
<resources>
<resource>
<directory>${project.basedir}/src/main/resources/</directory>
<filtering>false</filtering> <!-- 没有需要处理的maven变量 -->
<includes>
<include>application.yml</include>
<include>application-*.yml</include>
<include>*.conf</include>
<include>*.properties</include>
<include>log4j*</include>
<include>i18n/**</include>
<include>static/**</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
Step 3: 执行maven命令生成发布包
mvn install
直接一步生成
mvn package + mvn exec:exec
两步生成
exe文件可直接双击运行
app/conf
里面有配置文件