java应用打包运行的4种方法

文章目录

    • 1、方法一:打成jar部署运行
    • 2、方法二:通过自制启动器的方式运行
    • 3、方法三:使用jpackage把java和jdk一起打包
    • 4、方法四:使用GraalVM编译为原生应用
      • 4.1、使用native-image-agent(Graalvm内工具)工具来收集这些运行库信息
      • 4.2、编译为原生应用,Window平台下为DFDiff.exe,Linux平台上为DFDiff
      • 4.3、把console程序转为GUI程序
      • 4.4、添加应用图标
      • 4.5、编译后文件
        • 4.5.1、Windows平台编译后得到的运行文件
        • 4.5.2、Linux平台编译后得到的运行文件
    • 5、小结
    • 6、附录jpackage参数
      • 6.1、通用选项
      • 6.2、用于创建运行时映像的选项
      • 6.3、用于创建应用程序映像的选项
      • 6.4、用于创建应用程序启动器的依赖于平台的选项:
      • 6.5、用于创建应用程序包的选项:
      • 6.6、用于创建应用程序包的与平台相关的选项:
      • 6.7、jpackage 示例

本文主要介绍java应用编译打包后运行的方法。
本文以DFDiff:( https://gitee.com/penngo/dfdiff)项目为例子,介绍打包运行的方法

使用maven生成jar包:DFDiff-1.2.0-jar-with-dependencies.jar

mvn package

1、方法一:打成jar部署运行

这个方法需要单独安装JDK,然后在命令行下启动,可以单独制作启动脚本。
window下bat启动脚本

# 1、如果依赖包也打成同一个jar
@echo off
@REM 如果没有设置系统环境变量,如果在脚本中指定JDK
SET JAVA_HOME=C:\Program Files\Java\bellsoft\jdk-17.0.9
SET PATH=%JAVA_HOME%/bin;%PATH%;

@REM 936设为GBK编译, 65001设为UTF编译
chcp 65001  
java -jar DFDiff-1.2.0-jar-with-dependencies.jar


# 2、如果依赖包独立,本文不使用该方法,仅供打包其它项目时参考
@rem windows
@echo off
set project_home=%~dp0
echo %project_home%
setlocal enabledelayedexpansion
SET class_path=%project_home%DFDiff-1.2.0-jar-with-dependencies.jar
for /r %project_home%/lib %%i in (*.jar) do (
	rem echo %%i
	set class_path=!class_path!;%%i
)
echo %class_path%
java -Xms512m -Xmx512m -classpath %class_path% com.penngo.gui.dfdiff.DFMain
rem pause

Linux下shell启动脚本

# 1、如果依赖包也打成同一个jar
export JAVA_HOME=/usr/lib/jvm/bellsoft-java17.x86_64
export PATH=$JAVA_HOME/bin:$PATH
java -jar DFDiff-1.2.0-jar-with-dependencies.jar

# 2、如果依赖包独立,本文不使用该方法,仅供打包其它项目时参考
export JAVA_HOME=/usr/lib/jvm/bellsoft-java17.x86_64
export PATH=$JAVA_HOME/bin:$PATH

cd `dirname $0`
echo `pwd`

class_name=com.penngo.gui.dfdiff.DFMain
project_home=$(pwd)
class_path=
function libjars(){
for file in $project_home/lib/*
do
if [ -f $file ]
then
 #echo $file   
 class_path="$class_path$file:"
fi
done
}

libjars
class_path="$class_path:$project_home/DFDiff-1.2.0-jar-with-dependencies.jar"
export CLASSPATH=$CLASSPATH:$class_path
java -Xms512m -Xmx512m -Dproject.dir="$project_home" $class_name

2、方法二:通过自制启动器的方式运行

本文使用go来制作启动器,也可以使用其它能编译为原生应用的语言(C/C++,rust等)来制作,启动器的主要用来代替Window/Linux的shell脚本来启动java应用,
main.go源码

package main
import (
	"fmt"
	"os"
	"os/exec"
	"runtime"
)

func main() {
	var cmd *exec.Cmd
	fmt.Println("GOOS====", runtime.GOOS)
	if runtime.GOOS == "windows" {
	    // window下调用java启动
		cmd = exec.Command("jbr\\bin\\java.exe", "-jar", "DFDiff-1.2.0-jar-with-dependencies.jar")

	} else {
	    // 其它平台,Linux下调用java启动
		cmd = exec.Command("jbr/bin/java", "-jar", "DFDiff-1.2.0-jar-with-dependencies.jar")
	}
	cmd.Stdout = os.Stdout
	if err := cmd.Run(); err != nil {
		fmt.Println("could not run command: ", err)
	}
}

执行编译命令,生成可执行程序

go build main.go

window下生成main.exe运行程序,linux下生成main运行程序
默认下生成命令行下运行的控制台程序,运行时会带一个黑色命令行窗体。
window下转换为桌面应用和添加图标的方法

# winodw:console转为GUI, 
editbin /subsystem:windows main.exe

# winodw:添加图标
RCEDIT.exe /I main.exe logo.ico

editbin工具:https://learn.microsoft.com/zh-cn/cpp/build/reference/editbin-options?view=msvc-160
RCEDIT工具:https://github.com/poidasmith/winrun4j/releases/

使用jlink生成运行时(精简JRE)

# window下用jlink.exe,Linux下用jlink
jlink.exe --module-path jmods --add-modules java.desktop,java.logging,jdk.management,java.sql --output jbr

windown最终生成目录如下:linux下目录类似,只是对应的运行程序没有.exe后缀
java应用打包运行的4种方法_第1张图片

window下双击main.exe运行,Linux下双击main程序运行

3、方法三:使用jpackage把java和jdk一起打包

jpackage是JDK14后新增的独立打包的工具,同时会借助jlink工具按模块需要生成精简的JRE(java运行时),执行下边命令生成

jpackage --type app-image --name DFDiff --input target --app-version 1.2.0 --copyright gitee.com/penngo --vendor gitee.com/penngo --icon logo.ico --add-modules java.desktop,java.logging,jdk.management,java.sql --main-jar DFDiff-1.2.0-jar-with-dependencies.jar --dest dist

window下执行jpackage后生成的文件,双击DFDiff.exe运行
java应用打包运行的4种方法_第2张图片

Linux下执行jpackage后生成的文件,shell环境下输入命令./DFDiff运行
java应用打包运行的4种方法_第3张图片

4、方法四:使用GraalVM编译为原生应用

4.1、使用native-image-agent(Graalvm内工具)工具来收集这些运行库信息

java -agentlib:native-image-agent=config-output-dir=META-INF/native-image -jar DFDiff-1.0.0-jar-with-dependencies.jar
# 或
mvn -Pnative -Dagent exec:exec@java-agent

4.2、编译为原生应用,Window平台下为DFDiff.exe,Linux平台上为DFDiff

native-image --verbose --no-fallback -H:ConfigurationFileDirectories=META-INF/native-image --link-at-build-time --allow-incomplete-classpath -jar DFDiff-1.0.0-jar-with-dependencies.jar DFDiff
# 或
mvn -DskipTests=true -Pnative -Dagent package

4.3、把console程序转为GUI程序

Grallvm编译后的原生应用默认为控制台运行,window下运行时带黑色窗体,可以通过以下命令转为GUI程序。
editbin使用介绍:https://learn.microsoft.com/zh-cn/cpp/build/reference/editbin-options?view=msvc-160

editbin /subsystem:windows DFDiff.exe

4.4、添加应用图标

window下修改应用图标可以使用第三方工具WinRun4J:https://github.com/poidasmith/winrun4j

RCEDIT.exe /I DFDiff.exe logo.ico

4.5、编译后文件

4.5.1、Windows平台编译后得到的运行文件

java应用打包运行的4种方法_第4张图片

4.5.2、Linux平台编译后得到的运行文件

java应用打包运行的4种方法_第5张图片

5、小结

  • 方法一是打成Jar,使用shell脚本启动是最常用的打包运行方式,打包发布不会存在兼容问题。运行时会显示两个进程:shell进程与java进程。
  • 方法二是在方法一基础上,简化shell的启动方式,但是启动器需要在每个平台上编译一次。运行时会显示两个进程:启动器进程与java进程。
  • 方法三是JDK自带的工具打包,与方法二相比,省掉自己编写启动器的工具。运行时会显示两个相同名称的应用进程。
  • 方法四是目前新的方式,能显著提高性能,但由于应用使用反射等技术原因,可能需要手动编写反射类,与前边3种方法相比,有一点的上手难度,同样也由此造成与前边三个方法相比,兼容性相对差。运行时只显示一个进程。

6、附录jpackage参数

6.1、通用选项

--type-t <键入字符串>
#要创建的包的类型
#有效值为:{"app-image", "exe", "msi", "rpm", "deb", "pkg", "dmg"}
#如果未指定此选项,则将创建一个与平台相关的默认类型。

--app-version <版本>
#应用程序和/或软件包的版本

--copyright <版权字符串>
#应用程序的版权。

--description <说明字符串>
#应用程序的说明。

--help-h
#将包含当前平台的每个有效选项的列表和说明的用法文本打印到输出流中,然后退出。

--name-n <name>
#应用程序和/或程序包的名称。

--dest-d <输出路径>
#生成输出文件的放置路径
#默认为当前工作目录。(绝对路径或相对于当前目录)。

--temp <文件路径>
#用于创建临时文件的新目录或空目录的路径(绝对路径或相对于当前目录的路径)。
#如果指定,则在任务完成时不会删除临时目录,必须手动删除。
#如果未指定,则在任务完成后将创建并删除临时目录。

--vendor <字符串>
#应用程序的供应商。

--verbose
#启用详细输出。

--version
#将产品版本打印到输出流并退出。 作者:蔡广 https://www.bilibili.com/read/cv14523427/ 出处:bilibili

6.2、用于创建运行时映像的选项

--add-modules <模块名称> [<模块名称>...],
#以逗号 (",") 分隔的要添加的模块列表。
#此模块列表以及主模块(如果指定)将作为 --add-module 参数传递给 jlink。如果未指定,则仅使用主模块(如果指定了 --module)或默认模块集(如果指定了 --main-jar)。
#此选项可以多次使用。

--module-path 或 -p <模块路径>...
#文件.路径分隔符分隔的路径列表。
#每个路径要么是模块的目录,要么是模块化 jar 的路径,并且是绝对的或相对于当前目录的。
#此选项可以多次使用。

--jlink-options <jlink选项>
#要传递给 jlink 的以空格分隔的选项列表
#如果未指定,则默认为"--strip-native-commands --strip-debug --no-man-pages --no-header-files"
#此选项可以多次使用。

--runtime-image <文件路径>
#将复制到应用程序映像中的预定义运行时映像的路径(绝对路径或相对于当前目录的路径)。
#如果未指定 --runtime-image,jpackage 将运行 jlink 以使用以下选项创建运行时映像:--strip-debug、--no-header-files、--no-man-pages 和 --strip-native-commands。 

6.3、用于创建应用程序映像的选项

--icon<图标文件路径>
#应用程序捆绑包图标的路径(绝对路径或相对于当前目录的路径)。

--input-i <输入路径>
#包含要打包的文件的输入目录的路径(绝对路径或相对于当前目录的路径)。
#输入目录中的所有文件都将打包到应用程序映像中。
用于创建应用程序启动器的选项:
--add-launcher <启动器名称>=<文件路径>
#启动器的名称,以及包含键、值对列表(绝对路径或相对于当前目录)的属性文件的路径。
#可以使用键"模块","添加模块","主jar","主类","参数","java选项","应用程序版本","图标"和"win-console"。
#这些选项将添加到原始命令行选项中,或用于覆盖原始命令行选项,以生成其他备用启动器。主应用程序启动器将从命令行选项构建。可以使用此选项构建其他替代启动器,并且可以多次使用此选项来构建多个其他启动器。

--arguments <主类参数>
#如果没有向启动器提供命令行参数,则传递给主类的命令行参数。
#此选项可以多次使用。

--java-options <java选项>
#要传递给 Java 运行时的选项。
#此选项可以多次使用。

--main-class <类名>
#要执行的应用程序主类的限定名称。
#仅当指定了 --main-jar 时,才能使用此选项。

--main-jar <jar文件>
#应用程序的主 JAR;包含主类(指定为相对于输入路径的路径)。
#可以指定 --module 或 --main-jar 选项,但不能同时指定两者。

--module-m <模块名称>/<主类>]
#应用程序的主模块(以及可选的主类) 此模块必须位于模块路径上。
#指定此选项后,主模块将在 Java 运行时映像中链接。可以指定 --module 或 --main-jar 选项,但不能同时指定两者。

6.4、用于创建应用程序启动器的依赖于平台的选项:

Windows 平台选项(仅在 Windows 上运行时可用):

--win-console
#为应用程序创建控制台启动器,应为需要控制台交互的应用程序指定启动器

macOS 平台选项(仅在 macOS 上运行时可用):

--mac-package-identifier <ID 字符串>
#唯一标识适用于 macOSX 的应用程序的标识符。
#默认为主类名。
#只能使用字母数字 (A-Z、a-z、0-9)、连字符 (-) 和句点 (.) 字符。

--mac-package-name <名称字符串>
#应用程序在菜单栏中显示的名称。
#这可能与应用程序名称不同。
#此名称的长度必须少于 16 个字符,并且适合在菜单栏和应用程序"信息"窗口中显示。默认为应用程序名称。

--mac-bundle-signing-prefix <前缀字符串>
#对应用程序捆绑包进行签名时,此值将作为所有需要签名且没有现有捆绑包标识符的组件的前缀。

--mac-sign
#请求对捆绑包进行签名。

--mac-signing-keychain <文件路径>
#用于搜索签名标识的钥匙串的路径(绝对路径或相对于当前目录的路径)。
#如果未指定,则使用标准钥匙串。

--mac-signing-key-user-name <团队名称>
#Apple 签名身份名称中的团队名称部分。
#例如"开发者 ID 应用程序:<团队名称>"

6.5、用于创建应用程序包的选项:

--app-image <文件路径>
#用于生成可安装包的预定义应用程序映像的位置(绝对路径或相对于当前目录)。
#请参阅创建应用映像模式选项以创建应用程序映像。

--file-associations <文件路径>
#包含键、值对列表(绝对路径或相对于当前目录)的属性文件的路径。
#键"扩展","哑剧类型","图标"和"描述"可用于描述关联。
#此选项可以多次使用。

--install-dir <文件路径>
#OS X 或 Linux 上应用程序安装目录的绝对路径。应用程序的安装位置的相对子路径,例如 Windows 上的"程序文件"或"AppData"。

--license-file <文件路径>
#许可证文件的路径(绝对路径或相对于当前目录的路径)。

--resource-dir <路径>
#覆盖 jpackage 资源的路径(绝对路径或相对于当前目录的路径)。
#jpackage 的图标、模板文件和其他资源可以通过向此目录添加替换资源来覆盖。

--runtime-image <文件路径>
#要安装的预定义运行时映像的路径(绝对路径或相对于当前目录的路径)。
#创建运行时安装程序时需要该选项。

6.6、用于创建应用程序包的与平台相关的选项:

Windows 平台选项(仅在 Windows 上运行时可用):

--win-dir-chooser
#添加一个对话框,使用户能够选择安装产品的目录。

--win-menu
#将应用程序添加到系统菜单。

--win-menu-group <菜单组名称>
#此应用程序所在的"开始"菜单组。

--win-per-user-install
#请求基于每个用户执行安装。

--win-shortcut
#为应用程序创建桌面快捷方式。

--win-upgrade-uuid <id 字符串>
#与此程序包的升级关联的 UUID

Linux 平台选项(仅在 Linux 上运行时可用):

--linux-package-name <包名称>
#Linux 包的名称,默认为应用程序名称。

--linux-deb-maintainer <电子邮件地址>
#捆绑包.deb维护者。

--linux-menu-group <菜单组名称>
#此应用程序所在的菜单组。

--linux-package-deps
#应用程序所需的包或功能

--linux-rpm-license-type <键入字符串>
#许可证类型(RPM .spec 的"许可证:<值>")。

--linux-app-release <发布字符串>
#RPM 的发布值.spec 文件或 DEB 控制文件的 Debian 修订版值。

--linux-app-category <类别字符串>
#RPM .spec 文件或 DEB 控制文件的节值的组值。

--linux-shortcut
#为应用程序创建快捷方式

6.7、jpackage 示例

#生成适合宿主系统的应用包:
#对于模块化应用:
jpackage -n name -p modulePath -m moduleName/className
#对于非模块化应用程序:
jpackage -i inputDir -n name  --main-class className --main-jar myJar.jar
#从预先构建的应用程序映像:
jpackage -n name --app-image appImageDir

#生成应用镜像:
#对于模块化应用:
jpackage --type app-image -n name -p modulePath -m moduleName/className
#对于非模块化应用程序:
jpackage --type app-image -i inputDir -n name --main-class className --main-jar myJar.jar
#要为 jlink 提供您自己的选项,请单独运行 jlink:
jlink --output appRuntimeImage -p modulePath -m moduleName --no-header-files [<additional jlink options>...]
jpackage --type app-image -n name -m moduleName/className --runtime-image appRuntimeImage

#生成 Java 运行时包:
jpackage -n name --runtime-image <runtime-image> 

参考自官方:https://docs.oracle.com/en/java/javase/17/docs/specs/man/jpackage.html

你可能感兴趣的:(java,java,开发语言)