无需JVM!GraalVM打造Windows平台零依赖Java应用

作为编程语言领域的常青树,Java凭借其卓越的跨平台特性与稳健的架构设计,历经三十载 技术迭代仍稳居行业核心地位。从企业级分布式系统到高并发微服务架构,从跨平台桌面应用到全场景移动开发,其技术栈已深度渗透电力金融电商 等关键领域,构建起覆盖全球数亿终端的数字基础设施。尽管面临新兴语言的挑战与争议 ,但经过千万级核心业务系统的实战检验,Java至今仍是众多IT架构的底层基石------这一事实本身,便是对其技术生命力与开发者信任度的最佳诠释。

长期以来,Java企业级服务 开发领域占据着主导地位 ,其基于Web的分布式系统架构已成为行业标准范式。桌面应用则似乎与其无缘,然而事实并非如此------Java 在桌面领域其实早已展开诸多尝试与努力,这种认知偏差掩盖了其技术演进中鲜为人知的探索历程。

回溯至Java早期版本,Swing组件库的推出便彰显了其对桌面市场的野心。这套基于AWT的轻量级UI框架,不仅配备了可视化IDE开发工具(如NetBeans的GUI Builder),通过拖拽式界面设计降低了开发门槛,更催生了众多第三方主题套件,使Swing应用能够轻松实现macOS风格的拟物化界面设计,兼顾美观与不错的运行性能。

随着技术迭代,Oracle在JDK 7中正式集成JavaFX 框架,标志着Java桌面战略的重大升级。彼时微软推出的 WPF 因界面精美而轰动业界,而对 Java 桌面生态抱有信念的开发者,也将 JavaFX 称作"Java 界的 WPF",折射出对桌面UI框架的共同追求。然而现实往往是残酷的:Java 在桌面开发领域始终处于非主流地位,市场份额不足3%,最终导致Oracle在JDK 11后移除了JavaFX默认集成。

回望过去,我常思考是什么阻碍了Java在桌面领域的发展呢 ?基于多年一线开发实践,笔者认为JVM的架构设计或许正是核心症结所在。众所周知,Java需编译为字节码并在JVM上运行,这套机制成就其跨平台能力并在服务器领域大获成功,但却给桌面应用带来了较高的部署门槛 ------用户必须额外安装JVM,无形中增加了安装成本理解负担 。反观原生开发方案 (如C++/Qt),其编译产物为可直接执行的二进制文件,完美契合用户对桌面软件"下载即用"的预期。这种技术路径差异造就了根本性的体验鸿沟。

我一直在寻找一种能将Java直接编译为二进制文件(或者说,原生的EXE程序)的方法。过去遇到的多是"套壳"方案------它们为Java程序包上一个EXE外壳,看似与普通可执行文件无异,运行时却依然依赖JVM。直到最近接触了GraalVM ,我才感到真正的突破。它从根本上解决了这一问题,能将Java代码直接编译为独立的本地可执行文件。这种真正意义上的原生编译方式,令人激动,带来的喜悦远超言语所能形容------这不仅是工具的进化,更是Java开发范式的一次重大跃迁。

一、GraalVM介绍

GraalVM 是一款由 Oracle 开发的高性能 通用虚拟机,它不仅显著提升 了Java、Kotlin、Scala等JVM语言的执行效率 ,也支持JavaScript、Python、Ruby、R等多种语言的无缝集成。凭借先进的即时编译与跨语言互操作能力,重新定义了 Java 运行时的能力边界。其深度融合了解释执行、JIT编译与AOT静态编译等技术 ,不仅实现了接近C++的峰值性能,更带来了毫秒级启动延迟 的重大突破。这些特性使其尤其适用于云原生微服务Serverless等对性能与启动速度极为敏感的场景。

作为GraalVM的核心革新Native Image(AOT 编译) 技术采用静态分析,将 Java 应用及其依赖项(包括 SubstrateVM 轻量级运行时)直接编译为独立的原生可执行文件,从而彻底消除 JVM 的启动开销。不过,这项技术也有其限制,例如对于反射、动态代理等动态特性,开发者需通过配置文件(如 reflect-config.json)进行显式声明,方可确保其在编译后正常运行。

二、GraalVM前世今生

GraalVM 的发展历程始于 2012 ,其前身源于 Oracle Labs 的"Maxine VM"研究项目,最初目标是用 Java 实现一个更高效、更灵活的 JIT 编译器,以替代 HotSpot 中的 C1 编译器。

随着云原生微服务 架构的兴起,面对Kubernetes与Serverless引发的性能革命,传统 JVM 在启动时间与内存占用上的瓶颈日益凸显,Oracle 认识到仅优化 JIT 已无法满足这些新兴场景的虚需求。

2018 年 ,Oracle 正式发布跨平台(Linux、macOS、Windows)的 GraalVM。其核心创新包括Native Image(AOT 编译)Truffle 框架 ------后者支持多语言混合编程,实现了零开销互调用 ,打破了 JVM 长期以来的语言边界,构建起了真正的**"Write Once, Run Anywhere"** 新范式。Oracle 希望借此推动 Java 生态与其他语言生态的融合,进一步拓展 Java 的技术影响力。

2020 年后,Native Image 技术趋于稳定,对反射、动态代理等复杂动态特性的支持也逐步完善。Helidon、Micronaut、Quarkus 及 Spring Boot 等主流框架相继提供对 Native Image 的支持,大幅降低了原生应用的开发门槛。

进入 2025 年 ,GraalVM 已成为云原生 Java 应用的主流选择 ,尤其在 Serverless 与容器化部署场景中表现卓越 。据Gartner 2024年报告,GraalVM在FaaS市场的占有率已达63% ,AWS Lambda、Azure Functions等主流Serverless平台均将其列为Java运行时首选。Twitter、Uber、SAP等企业也率先采用GraalVM,其中Twitter将微服务迁移至GraalVM后,冷启动时间从分钟级降至秒级 ,资源成本降低30%

回顾全程 ,GraalVM 从最初致力于构建下一代 JIT 编译器的研究项目,逐步演进为一个支持多语言、具备 AOT 编译能力的通用运行时平台。这一演变不仅源于技术本身的迭代,也映射出云计算时代效率轻量跨语言集成的持续追求,以及 Oracle 在战略层面对未来运行时的长远布局。

三、环境搭建

前面介绍了这么多,接下来上点干货。带领大家零基础入门GraalVM。所谓"工欲善其事必先利其器"呀,我们先把环境搭建起来。

严格按照下面的顺序流程,即可轻松完成环境搭建,不踩坑,一次性成功!So Easy!O(∩_∩)O

  • 环境说明:
    • 操作系统:Window 11
    • JDK 17

1、安装Microsoft C++编译器

GraalVM Native Image技术,是把Java程序编译为本地二进制程序,所以要用到C++编译器。网上常见教程往往推荐大家安装 Visual Studio 那个重量级的大家伙,其实并不必要(浪费空间),所谓缺啥补啥。我们只需具备可用的 C++ 编译工具链即可。

Microsoft C++ 生成工具 - Visual Studiohttps://visualstudio.microsoft.com/zh-hans/visual-cpp-build-tools/

++注:此处下载的是在线安装包,所以安装过程较长,请耐心等待...++

在线安装包内部下载完安装包后,会弹出如下画面,请按如图所示勾选相关配置,保持一致。

  • 安装完毕后,开始菜单中出现如下图所示:

2、安装GraalVM

Download GraalVMhttps://www.graalvm.org/downloads/#注:下载 GraalVM ,需要登录 Oracle 账号。

  • 安装方式:解压安装
  • 配置环境变量
bash 复制代码
JAVA_HOME=C:\DevTools\graalvm-jdk-17
bash 复制代码
GRAALVM_HOME=C:\DevTools\graalvm-jdk-17
bash 复制代码
#在 PATH 中 添加
%JAVA_HOME%/bin

++注:GraalVM 本质上是一个JDK,并完全通过了TCK测试,它在此基础上,增加了 AOT 与 Native Image 功能。理解这一点很重要哦。++

  • 验证安装是否成功
bash 复制代码
#输入命令
java --version

#输出如下内容表示成功
java 17.0.18 2026-01-20 LTS
Java(TM) SE Runtime Environment Oracle GraalVM 17.0.18+8.1 (build 17.0.18+8-LTS-jvmci-23.0-b80)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 17.0.18+8.1 (build 17.0.18+8-LTS-jvmci-23.0-b80, mixed mode, sharing)
bash 复制代码
#输入命令
native-image --version

#输出如下内容表示成功
native-image 17.0.18 2026-01-20
GraalVM Runtime Environment Oracle GraalVM 17.0.18+8.1 (build 17.0.18+8-LTS-jvmci-23.0-b80)
Substrate VM Oracle GraalVM 17.0.18+8.1 (build 17.0.18+8-LTS, serial gc, compressed references)

四、实战

1、实战项目一:Hello World

功能描述:输出 Hello World,并每隔1秒,在控制台打印一次系统时间。

a)编写源码:Hello.java

java 复制代码
import java.text.SimpleDateFormat;
import java.util.Date;

public class Hello {	

    public static void main(String[] args) {
        System.out.println("Hello World");    

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        while(true) {
            try {
                Thread.sleep(1000);
                String time = sdf.format(new Date());
                System.out.println(time);               
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

b)打开 C++ 编译环境:x64 Native Tools Command Prompt for VS

bash 复制代码
#输出如下内容,表示C++环境OK
**********************************************************************
** Visual Studio 2026 Developer Command Prompt v18.2.1
** Copyright (c) 2025 Microsoft Corporation
**********************************************************************
[DEBUG:ext\vcvars.bat] Found potential v145 version file: 'Microsoft.VCToolsVersion.VC.14.50.18.0.txt'
[DEBUG:ext\vcvars.bat] Testing v145 version file: 'Microsoft.VCToolsVersion.VC.14.50.18.0.txt'
[vcvarsall.bat] Environment initialized for: 'x64'

c)编译Java源码

bash 复制代码
javac Hello.java

d) 生成反射配置文件(可选)

若你的Java程序用到了反射等动态能力,则需要反射等配置文件。这些配置文件有两种生成方式:1、手动编写;2、通过工具自动生成(native-image-agent)

通过工具自动生成,如下所示:(本实例无使用,可跳过,此处展示,就是告诉大家此类情形如何处理)

输入如下命令:

bash 复制代码
java -agentlib:native-image-agent=config-output-dir=./META-INF/native-image Hello
  • config-output-dir:指定配置文件的输出目录
  • 尽可能多地操作你的程序(点击窗口、按钮、打开菜单等),让代理能捕捉到所有必要的运行时行为。
  • 操作完成后,正常关闭程序。

输出文件如下图所示:

e)编译Java程序为本地二进制程序

bash 复制代码
native-image Hello

f)测试

2、实战项目二:JavaFX桌面应用

功能描述:在JavaFX窗口中,实时显示系统时间。

a)创建Maven项目:javafx-demo

  • pom.xml
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zongjin</groupId>
    <artifactId>javafx-demo</artifactId>
    <version>1.0</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <javafx.version>21.0.10</javafx.version>
        <gluonfx.version>1.0.28</gluonfx.version>
    </properties>

    <build>
        <plugins>
            <!-- JavaFX Maven 插件 -->
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.8</version>
                <configuration>
                    <mainClass>com.zongjin.ui.Hello</mainClass>
                </configuration>
            </plugin>

            <!-- GluonFX Maven 插件 -->
            <!-- 简化 Native Image 打包过程,自动生成反射等配置文件 -->
            <plugin>
                <groupId>com.gluonhq</groupId>
                <artifactId>gluonfx-maven-plugin</artifactId>
                <version>${gluonfx.version}</version>
                <configuration>
                    <!-- 指定你的主类 -->
                    <mainClass>com.zongjin.ui.Hello</mainClass>
                    <!-- 可选:指定目标平台,如 desktop, android, ios -->
                    <target>host</target> <!-- 'host' 表示当前操作系统 -->
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>${javafx.version}</version>
        </dependency>
    </dependencies>
</project>
  • Hello.java
java 复制代码
package com.zongjin.ui;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * JavaFX 简单示例
 *
 * @Author Tommy
 * @Date 2026/1/27
 */
public class Hello extends Application {

    Label timeLabel = new Label();

    @Override
    public void start(Stage stage) throws Exception {
        // 创建BorderPane根容器
        BorderPane root = new BorderPane();
        root.setStyle("-fx-background-color: #1B1B1B; -fx-font-weight: bold; -fx-font-size: 18px;");

        // 1. 顶部区域 (TOP)
        Text title = new Text("Hello JavaFX");
        title.setStyle("-fx-fill: #fff");
        StackPane topPane = new StackPane();
        topPane.setAlignment(Pos.CENTER);
        topPane.getChildren().add(title);
        root.setTop(topPane);

        // 2. 中间区域 (CENTER)
        timeLabel.setStyle("-fx-text-fill: #fff");
        StackPane centerPane = new StackPane(timeLabel);
        centerPane.setAlignment(Pos.CENTER);
        root.setCenter(centerPane);

        // 配置舞台
        stage.setTitle("JavaFX 示例");
        stage.setScene(new Scene(root, 800, 600));

        // 设置定时器更新时间(每秒刷新)
        setupTimeUpdater();

        // 显示窗口
        stage.show();
    }

    void setupTimeUpdater() {
        Timeline timeline = new Timeline(
                new KeyFrame(Duration.ZERO, e -> updateTime()),
                new KeyFrame(Duration.seconds(1))
        );
        timeline.setCycleCount(Animation.INDEFINITE);
        timeline.play();
    }

    void updateTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = sdf.format(new Date());
        System.out.println(time);

        // 使用线程安全方式更新UI
        Platform.runLater(() -> {
            timeLabel.setText(time);
        });
    }

    public static void main(String[] args) {
        launch(args);
    }
}

b)打开 C++ 编译环境,通过Maven进行项目自动打包

bash 复制代码
mvn gluonfx:build

++注:首次编译JavaFX项目时,插件会自动下载JavaFX的静态库,时间可能会稍久一些,属于正常现象,请耐心等待...++

c)测试

五、总结

GraalVM 正在从一项前沿技术转变为现代Java开发的主流选项之一 。随着云原生 成为绝对主流,其AOT 编译能力将成为Java应用的关键竞争力 。同时,作为通用的多语言运行时,它也为探索异构计算 (如与原生代码交互)和新兴语言集成提供了基础。

到此分享结束!

是不是So Easy呢!大家赶快动手试试吧!O(∩_∩)O

Enjoy It!!!

相关推荐
沉默-_-2 小时前
力扣hot100普通数组(1)--C++
java·数据结构·算法·leetcode·数组
colicode2 小时前
java短信接口开发对接全流程:Spring Boot项目集成短信功能详解
java·开发语言·spring boot
HalvmånEver2 小时前
Linux:线程的概念、与进程区别及内核实现(线程一)
java·linux·运维
晓13132 小时前
第四章:Redis实战应用及常见问题(下篇)
java·数据库·缓存·wpf
KubeSphere 云原生2 小时前
云原生周刊:对 Docker 镜像的更改持久保存
docker·云原生·容器
csdn_aspnet2 小时前
Go语言常用算法深度解析:并发与性能的优雅实践
后端·golang·go
量子炒饭大师2 小时前
【C++入门】Cyber霓虹镜像城的跨域通行证 —— 【友元(friend)】跨类协作破坏封装性?友元函数与友元类为你架起特权桥梁!
java·开发语言·c++·友元函数·友元类·friend
没有bug.的程序员2 小时前
Spring Cloud Stream:消息驱动微服务的实战与 Kafka 集成终极指南
java·微服务·架构·kafka·stream·springcloud·消息驱动
{Hello World}2 小时前
Java内部类:深入解析四大类型与应用
java·开发语言