【Java】脱离 JVM 约束 GraalVM + Liberica NIK + Spring + Docker 将 Java 编译为平台二进制可执行文件
目录
零、参考资料
1. Spring 教程官网
2. GraalVM 官网
3. Liberica NIK 官网
一、前言 -> GraalVM 技术作用
优点
缺点
CNB vs 传统构建方式对比
二、配置环境
1. 【Docker Desktop】Windows11安装 Docker Desktop 链接
2. 介绍 Windows 和 Linux 的 GraalVM & Liberica NIK JDK
1. 功能对比
(1) Native Image(AOT 编译)
(2) 多语言支持
2. 性能与优化
3. 适用场景
4. 总结
3. 下载 Windows 和 Linux 的 Liberica NIK JDK
1. 先择下载的是构建镜像的 JDK
2. 选择下载 Windows 版本和 Linux 的两个都下载
3. 安装 LibericaNIK-OpenJDK-21
3.1 Windows:
3.2 WSL 2 Linux Ubantu 子系统:
1. 将下载好的 JDK 从 Windows 直接鼠标托复制到 Ubantu 子系统
2. 进入 WSL Ubantu 终端安装 JDK
编辑
3. 配置 Linux JDK 环境变量
3. 创建系统级 profile 文件
4. 更新系统配置
5. 测试验证系统级别 JDK 环境是否生效
6. (可选)如果在构建镜像的过程中提示未配置 JAVA_HOME
4. 配置编译可执行二进制文件 C++ 环境
4.1 Windows:
4.2 WSL 2 Linux Ubantu 子系统:
三、编译可执行二进制文件与Docker镜像
对 Java 文件编译二进制可执行文件
1. 创建 HelloNativeImage.java 文件
2. 使用 X64 Native Tools 终端编译
对 Java Maven 或 Gradle 的 JAR 包编译成可执行二进制文件
Maven 项目
编辑
Gradle 项目
CNB 自动编译构建成 Docker 镜像
CNB的核心概念
Maven 项目
Gradle 项目
四、总结
直接编译Java文件为二进制可执行文件
编译JAR包项目为二进制可执行文件
CNB直接构建Docker镜像
PS:本教程以大部分用户为例子,Windows 11 + WSL 2 + Linux (Ubantu) 子系统
注意:
- 你需要魔法才能操作!
- 你需要魔法才能操作!
- 你需要魔法才能操作!
零、参考资料
1. Spring 教程官网
链接:Spring 教程官网链接
2. GraalVM 官网
链接:GraalVM 官网链接
3. Liberica NIK 官网
链接:Liberica NIK 官网链接
一、前言 -> GraalVM 技术作用
优点
-
极简构建
-
无需本地安装 GraalVM 或 C/C++ 工具链,仅需 Docker + 一条 Maven 命令。
-
自动处理依赖、编译、打包全流程。
-
-
跨平台镜像
-
直接生成 Linux 容器镜像(如 Docker 镜像),无视开发机操作系统(Win/Mac/Linux)。
-
-
生产就绪
-
输出轻量级镜像(约 50-100MB),基于 Distroless 等安全基础镜像。
-
-
标准化流程
-
避免手动编写 Dockerfile,降低维护成本。
-
缺点
-
构建速度慢
-
首次构建需下载基础镜像和 Buildpack(约 5-10 分钟),后续构建仍需 2-5 分钟(GraalVM 编译本身耗时)。
-
-
调试复杂
-
容器内构建,原生镜像调试需额外配置(如
-H:±AllowIncompleteClasspath
等参数需通过环境变量传递)。
-
-
灵活性受限
-
深度定制 GraalVM 配置(如反射/资源动态加载)需修改 Buildpack 或使用自定义 Builder。
-
-
依赖网络
-
构建过程需实时下载云资源(Builder 镜像、依赖包),离线环境需预缓存。
-
CNB vs 传统构建方式对比
能力 | 传统GraalVM构建 | CNB构建 |
---|---|---|
依赖环境 | 需本地安装GraalVM、C/C++工具链 | 仅需Docker,无需本地GraalVM |
跨平台支持 | 需为不同OS单独编译 | 直接生成跨平台Docker镜像 |
构建流程复杂度 | 高(手动配置) | 低(一键命令) |
输出结果 | 本地可执行文件(如.exe) | 容器镜像(含原生可执行文件) |
适用场景 | 本地测试 | 生产容器化部署 |
典型应用场景
-
Serverless/FaaS平台
快速启动和低内存占用(如AWS Lambda),响应延迟敏感型业务59。 -
Kubernetes环境
结合CNB生成的轻量镜像,实现高效扩缩容和资源利用510。 -
持续集成流水线
通过CNB标准化构建流程,提升CI/CD效率
二、配置环境
1. 【Docker Desktop】Windows11安装 Docker Desktop 链接
往期:【Docker Desktop】Windows11安装 Docker Desktop
2. 介绍 Windows 和 Linux 的 GraalVM & Liberica NIK JDK
PS:
GraalVM 和 Liberica NIK(Native Image Kit)都是基于 OpenJDK 的 JDK 发行版,但它们在设计目标、功能特性和适用场景上有所不同。以下是两者的对比分析:
1. 功能对比
(1) Native Image(AOT 编译)
-
GraalVM
-
预装
native-image
-
原生支持
native-image
工具,可将 Java 应用编译为独立可执行文件。 -
适用于 Spring Boot、Micronaut、Quarkus 等框架的云原生优化。
-
-
Liberica NIK
-
预装
native-image
,无需额外安装(如gu install native-image
)。 -
提供 Liberica NIK Core/Standard/Full 版本,其中 Full 版集成 JavaFX(官网下载对应支持 Java 界面编程编译的版本 Full 版本)
-
优化构建流程,适合直接用于生产环境。
-
(2) 多语言支持
-
GraalVM
-
支持 JavaScript、Python、Ruby、R、LLVM(如 C/C++)等语言互操作。
-
适用于多语言混合开发场景(如 Java + Python 脚本调用)。
-
-
Liberica NIK
-
仅支持 Java/JVM 语言,不包含 GraalVM 的多语言运行时(如 Truffle 框架)。
-
2. 性能与优化
对比项 | GraalVM | Liberica NIK |
---|---|---|
启动速度 | 极快(AOT 编译优化) | 同 GraalVM,但构建流程更简化 |
内存占用 | 低(原生镜像仅需必要资源) | 类似,但 BellSoft 优化了构建内存使用(如减少 JDK 体积)6 |
构建时间 | 较长(需静态分析) | 可能更快(预装优化工具链) |
3. 适用场景
-
选择 GraalVM:
-
需要多语言支持(如 Java + JS/Python)。
-
企业级应用,需 Oracle 技术支持(企业版)。
-
深度定制 AOT 编译(如复杂反射配置)。
-
-
选择 Liberica NIK:
-
简化 Native Image 构建(适合 CI/CD 流水线)。
-
仅需 Java 原生镜像,无需 GraalVM 多语言功能。
-
生产环境部署(如云原生微服务、Serverless)。
-
4. 总结
-
GraalVM 是更全面的高性能运行时,适合多语言和高级 AOT 优化。
-
Liberica NIK 是 轻量化的 GraalVM 子集,专注于提供更便捷的 Native Image 构建体验,适合纯 Java 云原生开发14。
如果需要 多语言支持 或 企业级特性,选择 GraalVM;如果仅需 快速构建 Java 原生镜像,Liberica NIK 是更优选择。
3. 下载 Windows 和 Linux 的 Liberica NIK JDK
链接:Liberica NIK 官网链接
1. 先择下载的是构建镜像的 JDK
2. 选择下载 Windows 版本和 Linux 的两个都下载
原因:
- 你可以编译成 Windows 的,也可以编译成 Linux 玩。
- 下载压缩包的或者是安装版的,我下载的是安装版本的,目的是让 Linux 自动配置。
- 注意我们用的 Windows WSL 2 Linux Ubantu 子系统,所以要装 DEB 格式的。
- 注意系统架构,X86 为 AMD ,在 安装 Docker Desktop 中有介绍。
- 我这里装至今主流 JDK 21 版本稳定版。
3. 安装 LibericaNIK-OpenJDK-21
3.1 Windows:
Windows 安装直接 双击安装包安装 后配置环境变量,这里不予演示
3.2 WSL 2 Linux Ubantu 子系统:
1. 将下载好的 JDK 从 Windows 直接鼠标托复制到 Ubantu 子系统
拉取到 /opt 目录下
注意:你可以用命令,我直接托会产生一个 Zone.ldentifier 后缀名 IDENTIFIER格式文件,用rm命令删除即可。
2. 进入 WSL Ubantu 终端安装 JDK
sudo apt install <全/相对>./包名.deb
3. 配置 Linux JDK 环境变量
1. 复制安装路径,在我们移动 JDK 安装包过来的 /opt 路径中
2. 配置编辑 Linux 系统级别环境变量
sudo nano /etc/environment
增加 JAVA_HOME 变量:
JAVA_HOME="安装路径 /opt/xxxxxx/xxxjdk 注意不要填 bin 目录"
键盘:Ctrl + O -> Enter 回车保存;Ctrl + X 退出;
3. 创建系统级 profile 文件
sudo nano /etc/profile.d/java.sh
添加内容:
#!/bin/sh
export JAVA_HOME=/opt/bellsoft/liberica-vm-core-23.1.7-openjdk21
export PATH=$PATH:$JAVA_HOME/bin
设置权限:
sudo chmod +x /etc/profile.d/java.sh
4. 更新系统配置
# 重新加载环境变量
source /etc/environment# 使所有用户生效
sudo su
source /etc/profile
exit
exit
关闭 WSL 子系统窗口,重新进入WSL
5. 测试验证系统级别 JDK 环境是否生效
# 检查系统级环境变量
echo $JAVA_HOME
echo $PATH# 验证 Java 命令
java -version
which java
6. (可选)如果在构建镜像的过程中提示未配置 JAVA_HOME
# 设置系统默认 Java
sudo update-alternatives --install "/usr/bin/java" "java" "$JAVA_HOME/bin/java" 1
sudo update-alternatives --set java "$JAVA_HOME/bin/java"# 同样设置 javac
sudo update-alternatives --install "/usr/bin/javac" "javac" "$JAVA_HOME/bin/javac" 1
sudo update-alternatives --set javac "$JAVA_HOME/bin/javac"
4. 配置编译可执行二进制文件 C++ 环境
4.1 Windows:
1. 下载开发工具(Spring GraalVM 有介绍,需要借助开发工具的 X64 Native 终端)
链接:下载 Visual Studio 开发工具官网链接
2. 注意安装时勾选使 <使用 C++ 的桌面开发>
4.2 WSL 2 Linux Ubantu 子系统:
各系统差异不同:
- 也是因为 Linux 系统中不同发行版对应 GraalVM 工具时的差异
- 解决:想在 Linux 系统中编译成二进制可执行文件的,直接操作报错后,丢给 AI ,让它给你命令装对应编译成平台可执行二进制文件的 C++ 依赖库!(我就是这么做的)
在WSL的Ubuntu终端中执行以下命令:
# 更新软件源
sudo apt update# 安装基础编译工具链(包含gcc, g++, make, libc-dev等)
sudo apt install -y build-essential# 安装GraalVM native-image所需的依赖库
sudo apt install -y zlib1g-dev libz-dev libstdc++-12-dev
三、编译可执行二进制文件与Docker镜像
注意:Windows 中编译和 Linux 中编译的操作有区别,这里我只要展示 Windows 的操作各位便可知!!!
对 Java 文件编译二进制可执行文件
1. 创建 HelloNativeImage.java 文件
public class HelloNativeImage {public static void main(String[] args) {System.out.println("Hello, Native Image!");}
}
2. 使用 X64 Native Tools 终端编译
用管理员身份运行
进入 HelloNativeImage.java 文件目录中
执行命令将 Java 文件编译成可执行二进制文件
# 编译字节码
javac HelloNativeImage.java# 生成本地可执行文件
native-image HelloNativeImage# 运行
.\HelloNativeImage
对 Java Maven 或 Gradle 的 JAR 包编译成可执行二进制文件
注意:其实就是最终将所有 java 文件的打包成 jar 包编译成可执行二进制文件。
Maven 项目
注意 IDEA 开发工具或官网构建的 maven 项目给的两个文件可执行文件:本质无需单独安装 Maven,根据项目指定的版本自动下载 Maven 库。
- mvnw:提供给 Linux / Mac 系统
- 使用相对路径前缀:./
- mvnw.cmd:提供给 Windows 系统
- 使用相对路径前缀:.\
进入项目根目录直接执行构建命令:
# Windows 系统执行命令
.\mvnw.cmd -Pnative -Dmaven.test.skip=true native:compile# Linux/Mac 系统执行命令
./mvnw -Pnative -Dmaven.test.skip=true native:compile
以下是命令 .\mvnw.cmd -Pnative -Dmaven.test.skip=true native:compile
的详细解析表格:
命令部分 | 含义 | 作用说明 | 技术细节 |
---|---|---|---|
.\mvnw.cmd | Maven Wrapper 脚本 (Windows) | 使用项目自带的 Maven 封装器(无需预装 Maven),确保构建环境一致性 | 替代全局安装的 mvn 命令 |
-Pnative | 激活 Maven Profile 名为 native | 启用专为 GraalVM Native Image 编译优化的配置(通常在 pom.xml 中定义) | Profile 可能包含: • Native Image 插件依赖 • 构建参数预设 • 资源配置文件 |
-Dmaven.test.skip=true | 设置 Maven 属性:跳过测试 | 不执行单元测试和集成测试,显著加速构建过程(Native Image 编译本身较慢) | 等效于:-DskipTests=true |
native:compile | 执行 Maven 插件的 compile 目标 (来自 native-maven-plugin ) | 触发 GraalVM Native Image 的编译过程,生成可执行文件 | 关联插件:org.graalvm.buildtools:native-maven-plugin |
完整命令效果 | 1. 跳过测试阶段 2. 加载 Native 专用配置 3. 调用 GraalVM 编译 Java 为本地可执行文件 | 输出文件路径:target/项目名 (无扩展名,如 demo.exe ) |
构建成功,在 target 目录下双击或直接命令运行:
Gradle 项目
gradle nativeCompile
CNB 自动编译构建成 Docker 镜像
注意:为了展示差异,这次我们选择在 Linux 子系统中操作
- 无需创建编辑 Dockerfile 文件
-
CNB 全自动一键构建
-
因为我这里本次使用的是 Windows 中的 Linux 子系统,需要保持 Windows 中 Docker Desktop 的程序在运行中。
在GraalVM与Spring Boot的整合中,CNB(Cloud Native Buildpacks) 是一个核心的自动化构建工具链,用于将Spring Boot应用编译为GraalVM原生镜像(Native Image)并打包成容器镜像。它的作用与价值主要体现在以下方面:
CNB的核心概念
-
自动化镜像构建
CNB是一种云原生镜像构建标准,由云原生基金会(CNCF)维护。它通过预定义的构建包(Buildpacks)自动化完成应用编译、依赖管理和容器镜像生成,无需开发者手动编写Dockerfile。 -
与GraalVM的集成
在Spring Boot 3.0中,CNB通过Paketo Buildpacks的native-image
构建包,调用GraalVM的AOT(Ahead-of-Time)编译能力,直接将Spring Boot应用编译为本地可执行文件,并嵌入轻量级容器镜像(如Distroless)
能力 | 传统GraalVM构建 | CNB构建 |
---|---|---|
依赖环境 | 需本地安装GraalVM、C/C++工具链 | 仅需Docker,无需本地GraalVM |
跨平台支持 | 需为不同OS单独编译 | 直接生成跨平台Docker镜像 |
构建流程复杂度 | 高(手动配置) | 低(一键命令) |
输出结果 | 本地可执行文件(如.exe) | 容器镜像(含原生可执行文件) |
适用场景 | 本地测试 | 生产容器化部署 |
Maven 项目
pom.xml 配置构建插件:
<plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId>
</plugin>
Linux 子系统中执行自动化构建命令:
./mvnw -Pnative -Dmaven.test.skip=true spring-boot:build-image
进入项目根目录执行命令
运行镜像:
docker images #查看所有镜像
docker run --rm -p 8080:8080 镜像地址/镜像名:标签
Gradle 项目
gradle bootBuildImage
四、总结
-
直接编译Java文件为二进制可执行文件
-
编译JAR包项目为二进制可执行文件
-
CNB直接构建Docker镜像
构建方式 | 命令 | 描述 | 输入 | 输出 | 适用场景 |
---|---|---|---|---|---|
直接编译Java文件 | native-image [Java类名] (需先 javac 编译为.class ) | 使用GraalVM的native-image 工具直接将Java类编译为原生可执行文件。 | .java 或.class 文件 | 独立原生可执行文件(如.exe ) | 简单单文件测试;无依赖的轻量级应用;快速验证原生编译可行性。 |
编译JAR包项目为二进制可执行文件 | .\mvnw.cmd -Pnative -Dmaven.test.skip=true native:compile (Windows) 或 ./mvnw -Pnative -Dmaven.test.skip=true native:compile (Unix) | 通过Maven调用GraalVM插件: 1. 激活 native Profile2. 跳过测试 3. 编译项目JAR包并生成原生可执行文件。 | 项目源代码(含pom.xm ) | 平台相关原生可执行文件 | 完整Spring Boot项目;需生成高性能独立可执行文件;避免Docker依赖的部署场景。 |
CNB直接构建Docker镜像 | ./mvnw -Pnative -Dmaven.test.skip=true spring-boot:build-image | 通过Spring Boot的CNB(Cloud Native Buildpacks)插件: 1. 跳过测试 2. 直接构建包含原生应用的Docker镜像(无需显式生成JAR)。 | 项目源代码(含pom.xml ) | Docker镜像(含原生应用) | 容器化部署场景;需快速生成生产级Docker镜像;与Kubernetes等云原生平台集成。 |