使用 GraalVM 将基本的 Java 项目打包成 EXE
使用 GraalVM 將基本的 Java 項目打包成 EXE
- GraalVM 的環(huán)境搭建
- 將基本的 Java 項目打包成 EXE
- 將 JAR 轉(zhuǎn)化為 EXE
- GraalVM 與 Java 中其它打包成 EXE 的方法對比
- 提醒與補充
運行環(huán)境:
-
GraalVM Enterprise 21.3.0
-
Java 語言級別:17
-
Maven 3.8.3
-
IntelliJ IDEA 2021.2.2 (Ultimate Edition)
-
Windows 10 教育版 64位
GraalVM 的環(huán)境搭建
GraalVM 有兩種版本,Community 和 Enterprise。其中,前者對應(yīng)于 OpenJDK,后者對應(yīng) Oracle JDK。需要根據(jù)自己的需要進行選擇,本文以 GraalVM Enterprise 21.3.0 為例。
GraalVM 版本選擇網(wǎng)址:https://www.graalvm.org/downloads/
下載 GraalVM Enterprise 21.3.0 需要進入 Oracle 官網(wǎng),網(wǎng)址:https://www.oracle.com/downloads/graalvm-downloads.html?selected_tab=1
先下載 Oracle GraalVM Enterprise Edition Core。下載完成之后,應(yīng)該會得到一個 zip 壓縮包。
再在剛才的頁面下載 Oracle GraalVM Enterprise Edition Native Image。這次得到的應(yīng)該是一個 JAR 包。
將前面的 zip 壓縮包置入自己喜歡的文件夾下解壓,解壓得到的就是 GraalVM 程序文件。與安裝 JDK 時類似,將含 bin 的目錄作為 GraalVM 的安裝目錄。設(shè)環(huán)境變量如下:
-
變量名:ORACLE_GRAALVM_HOME
變量值:C:\Program Files\Java\graalvm-ee-java17-21.3.0
-
變量名:GRAALVM_HOME
變量值:%ORACLE_GRAALVM_HOME%
-
變量名:Path
變量值:%GRAALVM_HOME%\bin
如果上面的環(huán)境變量設(shè)置成功,在 CMD 的任意路徑中輸入以下命令應(yīng)該能看到上面設(shè)置的路徑。
where javawhere gu
C:\>where java C:\Program Files\Java\graalvm-ee-java17-21.3.0\bin\java.exeC:\>where gu C:\Program Files\Java\graalvm-ee-java17-21.3.0\bin\gu.cmd
安裝 Native Image 包。Native Image 包就是前面下載的 JAR 包。輸入以下命令對 Native Image 進行本地安裝。
gu -L install Native Image 的 JAR 包路徑其中,Native Image 的 JAR 包路徑 要替換成實際的路徑。
GraalVM 的運行需要 Visual Studio 中的 MSVS 的支持,因此需要下載 Visual Studio。編寫本博客時,筆者下載的是 Microsoft Visual Studio Enterprise 2022 (64 位)。
Visual Studio 下載網(wǎng)址:https://visualstudio.microsoft.com/zh-hans/vs/
現(xiàn)在,Visual Studio 在官網(wǎng)上只會提供在線安裝包。下載完在線安裝包后,選擇安裝含 MSVS 的選項。
至此,GraalVM 的運行環(huán)境已經(jīng)搭成。下面將開始使用 GraalVM 進行打包。
將基本的 Java 項目打包成 EXE
建一個簡單的 Java 項目。此項目的路徑中不能有中文,否則后面 GraalVM 運行時會報錯。
package demo;public class OriginJava {public static void main(String[] args) {System.out.println("Hello, world.");} }制作 .class 文件,因為 GraalVM 只能直接對 .class 文件進行操作。
制作 .class 文件的方法有很多,這里只舉一例。借助于 Java 命令 javac。先打開 CMD 進入上述 Java 項目的包的根目錄,也就是文件夾 demo 所在的目錄。然后輸入如下命令制作 .class 文件。
javac 包名/類名輸入如下命令使用 MSVS 的環(huán)境。這個命令是用于設(shè)置臨時設(shè)置與 MSVS 相關(guān)的環(huán)境變量,因此每次總是要輸。
call "vcvars64.bat 的路徑"【踩坑提醒】
??如果不輸入以上命令,后面運行 native-image 時會有如下報錯:
Error: Default native-compiler executable 'cl.exe' not found via environment variable PATH Error: To prevent native-toolchain checking provide command-line option -H:-CheckToolchain Error: Use -H:+ReportExceptionStackTraces to print stacktrace of underlying exception [demo.hello:10212] [total]: 3,021.75 ms, 0.96 GB # Printing build artifacts to: D:\XXX.txt Error: Image build request failed with exit status 1vcvars64.bat 提供了 MSVS 的運行環(huán)境。雖然也可以通過設(shè)置 MSVS 的環(huán)境變量來代替,不過這樣要設(shè)置的環(huán)境變量會有很多。對于筆者的 Microsoft Visual Studio Enterprise 2022 (64 位),以上的命令為:
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"D:\OriginJava\src>call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" ********************************************************************** ** Visual Studio 2022 Developer Command Prompt v17.0.4 ** Copyright (c) 2021 Microsoft Corporation ********************************************************************** [vcvarsall.bat] Environment initialized for: 'x64'
在 .class 的包的根路徑中輸入以下命令制作 EXE。
native-image 包名.類名D:\OriginJava\src>native-image demo.OriginJava [demo.originjava:4128] classlist: 1,950.10 ms, 0.96 GB [demo.originjava:4128] (cap): 1,737.90 ms, 0.96 GB [demo.originjava:4128] setup: 4,282.33 ms, 0.96 GB [demo.originjava:4128] (clinit): 162.30 ms, 2.34 GB [demo.originjava:4128] (typeflow): 2,867.26 ms, 2.34 GB [demo.originjava:4128] (objects): 5,915.14 ms, 2.34 GB [demo.originjava:4128] (features): 1,771.20 ms, 2.34 GB [demo.originjava:4128] analysis: 11,311.80 ms, 2.34 GB [demo.originjava:4128] universe: 1,424.64 ms, 2.35 GB [demo.originjava:4128] (parse): 711.20 ms, 2.35 GB [demo.originjava:4128] (inline): 1,436.68 ms, 2.33 GB [demo.originjava:4128] (compile): 19,422.42 ms, 2.82 GB [demo.originjava:4128] compile: 22,571.05 ms, 2.82 GB [demo.originjava:4128] image: 1,395.47 ms, 2.82 GB [demo.originjava:4128] write: 753.49 ms, 2.82 GB [demo.originjava:4128] [total]: 43,933.93 ms, 2.82 GB # Printing build artifacts to: D:\OriginJava\src\demo.originjava.build_artifacts.txt
可以看出,當前目錄下已經(jīng)生成了一個 EXE 文件,可直接運行。
將 JAR 轉(zhuǎn)化為 EXE
GraalVM 還可以將 JAR 轉(zhuǎn)化為 EXE。
使用如下命令可以將 JAR 轉(zhuǎn)化為 EXE。但是,這樣轉(zhuǎn)化出來的 EXE 仍然依賴于 JDK,所以一般意義不大。
native-image -jar JAR 包的路徑使用如下命令可以產(chǎn)生無 JDK 依賴的 EXE。
native-image -jar -no-fallback JAR 包的路徑GraalVM 與 Java 中其它打包成 EXE 的方法對比
??但是相對于 Java 中其它打包成 EXE 的方法,如果 GraalVM 打包成功,GraalVM 可以說是最優(yōu)的方式。 Java 中其它打包成 EXE 的方式無非就如下幾種,或者是它們的變體。
-
方式 1:先生成 JAR,然后將運行 JAR 包的命令寫在一個腳本中,以后直接運行腳本即可。
但此方法本質(zhì)上是先運行 Java 虛擬機,然后再用 Java 虛擬機加載運行 Java 代碼。Java 虛擬機會占用較高的內(nèi)存,且在這種方式下,Java 項目無法擁有自己的父進程名,對外只顯示為 Java 虛擬機在運行。
-
方式 2:底層原理同方式 1,但將上面的腳本封裝成了一個 EXE。
這樣做能讓普通用戶不能直接操作底層的腳本命令,提高了一定的安全系數(shù)和用戶的友好度。除此之外,它跟方式 1 沒有太大的區(qū)別。但根據(jù)使用的封裝軟件不同,此 Java 項目可能擁有自己的進程名與圖標。
-
方式 3:底層原理同方式 2,但使用了一種 EXE 壓縮軟件將上面的 JAR 包與腳本封裝成了一個 EXE。
-
方式 4:底層原理同方式 3,但這種方式將 JRE 的相對路徑信息也儲存到了 EXE 中,這樣可以直接在此 EXE 附近放一個 JRE 文件,以后就可以在新電腦上無需先安裝 Java 即可馬上運行。
但這種方式需要向用戶提供 JRE,JRE 的體積一般都非常龐大。另外,這種方式本質(zhì)上與前面幾種方式一樣,也是先運行 Java 虛擬機,然后再用 Java 虛擬機加載運行 Java 代碼。而 Java 虛擬機會占用較高的內(nèi)存。
-
方式 5:前期步驟同方式 4,但額外借助了 Java 的一些內(nèi)置工具命令精簡了 JRE 體積,使得打包之后應(yīng)用體積大大減少。
但這種方式需要每次用人力去排除和篩選 JRE,然后編寫命令執(zhí)行,無一般的規(guī)律可尋,且誤操作之后可能導(dǎo)致打包后運行失敗,這會增加人力時間成本。另外,這種方式只是減少了打包之后應(yīng)用體積,而沒有減少運行內(nèi)存。
-
方式 6:這種方式不同前面的這幾種方式。它直接使用 Java 內(nèi)置的打包命令即可生成 EXE,而無需借助第三方制 EXE 的軟件。制好后可在新電腦上無需先安裝 Java 即可馬上運行。
但這種方式需要每次用人力進行文件布局和多次編寫命令執(zhí)行。另外,這種方式打包后的應(yīng)用,其運行時本質(zhì)上還是依賴于 Java 虛擬機。
-
方式 7:底層原理同方式 6,但它被嵌入到 Java 的一種構(gòu)建工具(如 Maven)的插件中,一定程序可以減少手動配置并適合離不開構(gòu)建工具的項目。除此之外,它跟方式 6 沒有太大的區(qū)別。
-
GraalVM 方式:這種方式不同前面的這幾種方式。它生成的 EXE 的運行無需借助 Java 虛擬機,更無需先安裝 Java,且無論是應(yīng)用體積還是運行內(nèi)存在所有的打包方式是都是最少的。
但它不能直接支持含 Java 反射、動態(tài)代理(如 CGLIB)的 Java 項目,需要每次用人力統(tǒng)計所有使用過 Java 反射、動態(tài)代理的類,無一般的規(guī)律可尋。另外,在所有的打包方式中,GraalVM 打包的耗時最長,CPU、內(nèi)存消耗都是最大的。
提醒與補充
-
本文只是給出使用 GraalVM 打包 Java 項目的基本方法。由于 GraalVM 使用的是 AOT 技術(shù),所以它不能直接用于打包含 Java 反射、動態(tài)代理的 Java 項目。一般來說,如果想對含 Java 反射、動態(tài)代理的 Java 項目使用 GraalVM 進行打包,必須提前向 GraalVM 提供一個列出了涉及 Java 反射、動態(tài)代理所有的類的 JSON 列表,否則,要么打包時會失敗,要么打包后的應(yīng)用在運行時會失敗。
-
對于純 JavaFX 項目的 GraalVM 打包,可見筆者的另一篇博客:
使用 GraalVM 將純 JavaFX 項目打包成 EXE:
https://blog.csdn.net/wangpaiblog/article/details/122850438
總結(jié)
以上是生活随笔為你收集整理的使用 GraalVM 将基本的 Java 项目打包成 EXE的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何使用 Java 中执行 Window
- 下一篇: Java RMI 入门