使用 GraalVM 将基本的 Java 项目打包成 EXE

使用 GraalVM 将基本的 Java 项目打包成 EXE

运行环境:

  • GraalVM Enterprise 21.3.0
  • Java 语言级别:17
  • Maven 3.8.3
  • IntelliJ IDEA 2021.2.2 (Ultimate Edition)
  • Windows 10 教育版 64位

GraalVM 的环境搭建

  1. GraalVM 有两种版本,Community 和 Enterprise。其中,前者对应于 OpenJDK,后者对应 Oracle JDK。需要根据自己的需要进行选择,本文以 GraalVM Enterprise 21.3.0 为例。

    GraalVM 版本选择网址:https://www.graalvm.org/downloads/

    在这里插入图片描述

  2. 下载 GraalVM Enterprise 21.3.0 需要进入 Oracle 官网,网址:https://www.oracle.com/downloads/graalvm-downloads.html?selected_tab=1

  3. 先下载 Oracle GraalVM Enterprise Edition Core。下载完成之后,应该会得到一个 zip 压缩包。

  4. 再在刚才的页面下载 Oracle GraalVM Enterprise Edition Native Image。这次得到的应该是一个 JAR 包。

  5. 将前面的 zip 压缩包置入自己喜欢的文件夹下解压,解压得到的就是 GraalVM 程序文件。与安装 JDK 时类似,将含 bin 的目录作为 GraalVM 的安装目录。设环境变量如下:

    • 变量名:ORACLE_GRAALVM_HOME

      变量值:C:\Program Files\Java\graalvm-ee-java17-21.3.0

    • 变量名:GRAALVM_HOME

      变量值:%ORACLE_GRAALVM_HOME%

    • 变量名:Path

      变量值:%GRAALVM_HOME%\bin

  6. 如果上面的环境变量设置成功,在 CMD 的任意路径中输入以下命令应该能看到上面设置的路径。

    where java

    where gu

    C:\>where java
    C:\Program Files\Java\graalvm-ee-java17-21.3.0\bin\java.exe
    
    C:\>where gu
    C:\Program Files\Java\graalvm-ee-java17-21.3.0\bin\gu.cmd
    12345
    
  7. 安装 Native Image 包。Native Image 包就是前面下载的 JAR 包。输入以下命令对 Native Image 进行本地安装。

    gu -L install Native Image 的 JAR 包路径

    其中,Native Image 的 JAR 包路径 要替换成实际的路径。

  8. GraalVM 的运行需要 Visual Studio 中的 MSVS 的支持,因此需要下载 Visual Studio。编写本博客时,笔者下载的是 Microsoft Visual Studio Enterprise 2022 (64 位)

    Visual Studio 下载网址:https://visualstudio.microsoft.com/zh-hans/vs/

  9. 现在,Visual Studio 在官网上只会提供在线安装包。下载完在线安装包后,选择安装含 MSVS 的选项。

    在这里插入图片描述

  10. 至此,GraalVM 的运行环境已经搭成。下面将开始使用 GraalVM 进行打包。

将基本的 Java 项目打包成 EXE

  1. 建一个简单的 Java 项目。此项目的路径中不能有中文,否则后面 GraalVM 运行时会报错。

    package demo;
    
    public class OriginJava {
        public static void main(String[] args) {
            System.out.println("Hello, world.");
        }
    }
    1234567
    
  2. 制作 .class 文件,因为 GraalVM 只能直接对 .class 文件进行操作。

  3. 制作 .class 文件的方法有很多,这里只举一例。借助于 Java 命令 javac。先打开 CMD 进入上述 Java 项目的包的根目录,也就是文件夹 demo 所在的目录。然后输入如下命令制作 .class 文件。

    javac 包名/类名

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

  4. 输入如下命令使用 MSVS 的环境。这个命令是用于设置临时设置与 MSVS 相关的环境变量,因此每次总是要输。

    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 1
    123456
    

  5. vcvars64.bat 提供了 MSVS 的运行环境。虽然也可以通过设置 MSVS 的环境变量来代替,不过这样要设置的环境变量会有很多。对于笔者的 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'
    123456
    
  6. .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
    123456789101112131415161718
    

    在这里插入图片描述

  7. 可以看出,当前目录下已经生成了一个 EXE 文件,可直接运行。

    在这里插入图片描述

将 JAR 转化为 EXE

  1. GraalVM 还可以将 JAR 转化为 EXE。

  2. 使用如下命令可以将 JAR 转化为 EXE。但是,这样转化出来的 EXE 仍然依赖于 JDK,所以一般意义不大。

    native-image -jar JAR 包的路径

  3. 使用如下命令可以产生无 JDK 依赖的 EXE。

    native-image -jar -no-fallback JAR 包的路径

GraalVM 与 Java 中其它打包成 EXE 的方法对比

但是相对于 Java 中其它打包成 EXE 的方法,如果 GraalVM 打包成功,GraalVM 可以说是最优的方式。 Java 中其它打包成 EXE 的方式无非就如下几种,或者是它们的变体。

  • 方式 1:先生成 JAR,然后将运行 JAR 包的命令写在一个脚本中,以后直接运行脚本即可。

    但此方法本质上是先运行 Java 虚拟机,然后再用 Java 虚拟机加载运行 Java 代码。Java 虚拟机会占用较高的内存,且在这种方式下,Java 项目无法拥有自己的父进程名,对外只显示为 Java 虚拟机在运行。

  • 方式 2:底层原理同方式 1,但将上面的脚本封装成了一个 EXE。

    这样做能让普通用户不能直接操作底层的脚本命令,提高了一定的安全系数和用户的友好度。除此之外,它跟方式 1 没有太大的区别。但根据使用的封装软件不同,此 Java 项目可能拥有自己的进程名与图标。

  • 方式 3:底层原理同方式 2,但使用了一种 EXE 压缩软件将上面的 JAR 包与脚本封装成了一个 EXE。

  • 方式 4:底层原理同方式 3,但这种方式将 JRE 的相对路径信息也储存到了 EXE 中,这样可以直接在此 EXE 附近放一个 JRE 文件,以后就可以在新电脑上无需先安装 Java 即可马上运行。

    但这种方式需要向用户提供 JRE,JRE 的体积一般都非常庞大。另外,这种方式本质上与前面几种方式一样,也是先运行 Java 虚拟机,然后再用 Java 虚拟机加载运行 Java 代码。而 Java 虚拟机会占用较高的内存。

  • 方式 5:前期步骤同方式 4,但额外借助了 Java 的一些内置工具命令精简了 JRE 体积,使得打包之后应用体积大大减少。

    但这种方式需要每次用人力去排除和筛选 JRE,然后编写命令执行,无一般的规律可寻,且误操作之后可能导致打包后运行失败,这会增加人力时间成本。另外,这种方式只是减少了打包之后应用体积,而没有减少运行内存。

  • 方式 6:这种方式不同前面的这几种方式。它直接使用 Java 内置的打包命令即可生成 EXE,而无需借助第三方制 EXE 的软件。制好后可在新电脑上无需先安装 Java 即可马上运行。

    但这种方式需要每次用人力进行文件布局和多次编写命令执行。另外,这种方式打包后的应用,其运行时本质上还是依赖于 Java 虚拟机。

  • 方式 7:底层原理同方式 6,但它被嵌入到 Java 的一种构建工具(如 Maven)的插件中,一定程序可以减少手动配置并适合离不开构建工具的项目。除此之外,它跟方式 6 没有太大的区别。

  • GraalVM 方式:这种方式不同前面的这几种方式。它生成的 EXE 的运行无需借助 Java 虚拟机,更无需先安装 Java,且无论是应用体积还是运行内存在所有的打包方式是都是最少的

    但它不能直接支持含 Java 反射、动态代理(如 CGLIB)的 Java 项目,需要每次用人力统计所有使用过 Java 反射、动态代理的类,无一般的规律可寻。另外,在所有的打包方式中,GraalVM 打包的耗时最长,CPU、内存消耗都是最大的。

提醒与补充

  • 本文只是给出使用 GraalVM 打包 Java 项目的基本方法。由于 GraalVM 使用的是 AOT 技术,所以它不能直接用于打包含 Java 反射、动态代理的 Java 项目。一般来说,如果想对含 Java 反射、动态代理的 Java 项目使用 GraalVM 进行打包,必须提前向 GraalVM 提供一个列出了涉及 Java 反射、动态代理所有的类的 JSON 列表,否则,要么打包时会失败,要么打包后的应用在运行时会失败。

  • 对于纯 JavaFX 项目的 GraalVM 打包,可见笔者的另一篇博客:

    使用 GraalVM 将纯 JavaFX 项目打包成 EXE:
    https://blog.csdn.net/wangpaiblog/article/details/122850438

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值