SpringBoot: 使用GraalVM编译native应用
曾今Go语言里让我最艳羡的两个特性,一个是Goroutine,一个是native编译。 Java 21的虚线程实现了类似Goroutine的能力。Spring Boot 3.x开始提供了GraalVM的支持,现在Spring Boot也能打包成native文件了。
这一篇文章的目标是用一个案例讲解如何将Spring Boot应用打包成native文件。整个过程主要是4步:
- 环境准备,讲解怎么安装GraalVM,安装本地编译器(gcc,cl)
- 测试工程,创建一个极简的Spring Boot应用,只有个Controller
- 编译打包,使用GraalVM、Maven将Spring Boot应用构建成可执行文件
- 测试运行,执行生成的可执行文件,访问Controller看是否正常
1. 环境准备
1. 前置条件
GraalVM依赖一些本地工具才能完成工作,这些工具包括:
- C的头文件
- glibc-devel
- zlib
- gcc
- libstdc++-static
不同的操作系统,采用的安装方式不同,在Linux下可以使用包管理工具安装,比如yum、apt等
Linux
yum install gcc glibc-devel zlib-devel
apt-get install build-essential libz-dev zlib1g-dev
Windows
Windows可以通过安装Visual Studio完成依赖包安装
- 安装Visual Studio Build Tools
- 安装Visual Studio
2. 安装GraalVM
从官网选择Java版本、平台来下载,下载的zip包解压即安装,接下来只要设置环境变量JAVA_HOME、PATH即可

- 设置GRAALVM_HOME为解压文件夹的根目录
- 设置PATH为解压文件夹下的bin
3. 验证安装
通过执行native-image --help,确认我们安装成功

4. 参考资料
关于GraalVM的安装过程,可以参考官方的Get Started文档: Getting Started with GraalVM
2. 测试工程
1. 创建工程
使用mvn archetype:generate根据archetype maven-archetype-quickstart生成一个最简单的Java项目。
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DgroupId=com.keyniu.dis -DartifactId=DiveInSpring -Dversion=0.1 -Dpackage=com.keyniu.dis -DinteractiveMode=false
2. 添加Spring Boot支持
修改pom.xml选择spring-boot-starter-parent作为parent,添加native-maven-plugin插件
<?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.keyniu.dis</groupId><artifactId>DiveInSpring</artifactId><version>0.1</version><name>DiveInSpring</name><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.0</version></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId></plugin></plugins></build></project>
3. 添加测试类
写一个最简单启动引导类,提供一个最简单的接口/hello,用于后续测试。
package com.keyniu.dis;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@SpringBootApplication
@RestController
public class DiveInMain {@GetMapping("/hello")public String hello(@RequestParam("name") String name) {return "hello," + name;}public static void main(String[] args) {SpringApplication.run(DiveInMain.class);}
}
3. 编译打包
1. 命令行窗口
为了让GraalVM能引用到VisualStudio的编译工具,我选择在x64 Native Tools窗口中运行接下来的命令。

在执行命令之前,确保你的环境变量设置正确,有添加GraalVM相关的配置
set GRAALVM_HOME=D:\Programs\GraalVM
set PATH=D:\Programs\GraalVM\bin;%PATH%
2. 进行native编译
在工程的根目录下执行mvn -Pnative native:compile,进行编译,最后会生成一个exe到工程的target目录下,输入如下
D:\Workspace\DiveInSpring>mvn -Pnative native:compile
...
Produced artifacts:D:\Workspace\DiveInSpring\target\DiveInSpring.exe (executable)
4. 测试运行
只需要在命令行里输入DiveInSpring.exe执行,可以看到只需要0.063s就能完成启动,这个项目如果通过java -jar启动的话大概耗时0.97s,还是快了很多的。打包后的exe文件大小是80M。

通过curl命令验证,接口正常提供服务

5. 使用建议
可以看到整个构建过程已经相当的顺畅,从可执行文件的大小,启动时间,内存占用都于明显的提升,应该说Spring + GraalVM离成熟应用已经不远了。由于GraalVM使用了Closed World Optimization,实际上这个可执行程序还是有一些限制的,主要是:
- Class初始化,有些初始化会在build期间完成,可以参考GraalVM文档: Class Initialization in Native Image
- 反射和动态代理,需要的编译期间完成
- 不支持JNI,如果有本地方法调用需要根据GraalVM提供的接口定制实现
- 执行时无法访问字节码,正常的debug、监控等用JVM TI实现的功能都不再可用
在SpringBoot中, 像profiles、 条件配置、 @Enable*等功能会受到影响,而其实这些特性正在被广泛使用,这些限制在完全解决之前实际使用还是有障碍的。关于可以执行文件的DEBUG、监控在GraalVM官网都已经有对应的文档,但是将它和公司内部的监控报警做集成还有一段路要走,已经看到黎明的曙光了。
A. 参考资料
- GraalVM构建Swing应用
- 使用GDB Debug由GraalVM构建的程序,Debug Native Executables with GDB
- 让可执行文件支持JFR,Build and Run Native Executables with JFR
- 手动创建Spring Boot工程
相关文章:
SpringBoot: 使用GraalVM编译native应用
曾今Go语言里让我最艳羡的两个特性,一个是Goroutine,一个是native编译。 Java 21的虚线程实现了类似Goroutine的能力。Spring Boot 3.x开始提供了GraalVM的支持,现在Spring Boot也能打包成native文件了。 这一篇文章的目标是用一个案例讲解如…...
9. MySQL事务、字符集
文章目录 【 1. 事务 Transaction 】1.1 事务的基本原理1.2 MySQL 执行事务的语法和流程1.2.1 开始事务1.2.2 提交事务1.2.3 回滚(撤销)事务实例1:一致性实例2:原子性 【 2. 字符集 和 校对规则 】2.1 基本原理2.2 查看字符集查看…...
为什么要学习数据结构和算法
前言 控制专业转码学习记录,本科没学过这门课,但是要从事软件行业通过相关面试笔试基础还是要打牢固的,所以通过写博客记录一下。 必要性 1.越是厉害的公司,越是注重考察数据结构与算法这类基础知识 2.作为业务开发,…...
CANoe仿真工程Switch控件关联dbc信号出现的问题及解决思路
小白学习CANoe仿真,参考CANoe-第2个仿真工程-XVehicle—1总线数据库设计(思路)_canoe vehicle-CSDN博客 CANoe-第2个仿真工程-XVehicle1总线数据库设计(操作)_canoe factor 参数什么意思-CSDN博客CANoe-第2个仿真工程…...
用开源模型MusicGen制作六一儿童节专属音乐
使用的是开源模型MusicGen,它可以根据文字描述或者已有旋律生成高质量的音乐(32kHz),其原理是通过生成Encodec token然后再解码为音频,模型利用EnCodec神经音频编解码器来从原始波形中学习离散音频token。EnCodec将音频信号映射到一个或多个并…...
Ps:批处理
Ps菜单:文件/自动/批处理 Automate/Batch 批处理 Batch命令可以对一个文件夹中的文件执行事先创建的动作 Actions,从而快速地完成大量的重复性操作,提升工作效率。 提示 1: 可以从 Adobe Bridge 中调用 Photoshop 的批处理命令。 …...
前端框架中的虚拟DOM和实际DOM之间的关系
聚沙成塔每天进步一点点 本文回顾 ⭐ 专栏简介前端框架中的虚拟DOM和实际DOM之间的关系1. 实际DOM(Real DOM)1.1 定义1.2 特点 2. 虚拟DOM(Virtual DOM)2.1 定义2.2 特点 3. 虚拟DOM的工作流程3.1 创建虚拟DOM3.2 比较虚拟DOM&…...
MySQL进阶——SQL性能分析
在上篇文章我们学习了MySQL进阶——存储引擎,这篇文章学习MySQL进阶——SQL性能分析。 SQL性能分析主要是从SQL语句执行频率、耗时时间、CPU使用情况和执行时表连接情况进行分析,常用的方法工具有:SQL执行频率、慢查询日志、profile详情和ex…...
在RT-Thread下为MPU手搓以太网MAC驱动-4
文章目录 MAC驱动里面对MDIO的支持MAC驱动与MDIO总线 这是个人驱动开发过程中做的一些记录,仅代表个人意见和理解,不喜勿喷 MAC驱动需要支持不同的PHY芯片 MAC驱动里面对MDIO的支持 在第一篇文章中提到对MAC设备做出了抽象,其中MAC抽象里面有…...
可的哥(Codigger)推出Monaco编辑器插件,提升编程体验
Monaco编辑器,作为业界领先的代码编辑器,在编程体验中发挥着不可或缺的重要作用,能够在多种编程语言和开发环境中表现出色,为开发者提供高效、便捷的编程环境。可的哥(Codigger)在应用商店上线Monaco编辑器…...
为什么选择mobx
对于React而言,大家熟能而详的是redux,但我们的项目用的是mobx,接下来就让我给你详细说下它的优势和不足,可以参考。 MobX是什么? MobX 是一种简单易用的状态管理库,它采用基于观察者的模式,可…...
如何解决段转储问题
非常恶心 ,这个问题困了我一个月,怀疑过代码有问题 ,怀疑过数据集没处理好,怀疑过环境没有配置好,尝试改动,跑过很多次,还是段转储报错卡住。。。 然后一个月荒废,打算放弃这个模型…...
【杂谈】AIGC之ChatGPT-与智能对话机器人的奇妙对话之旅
与智能对话机器人的奇妙对话之旅 引言 在数字时代的浪潮中,ChatGPT如同一位智慧的旅伴,它不仅能够与我们畅谈古今,还能解答我们的疑惑,成为我们探索知识海洋的得力助手。今天,就让我们走进ChatGPT的世界,…...
CentOS7配置国内清华源并安装docker-ce以及配置docker加速
说明 由于国内访问国外的网站包括docker网站,由于种种的原因经常打不开,或无法访问,所以替换成国内的软件源和国内镜像就是非常必要的了,这里整理了我安装配置的基本的步骤。 国内的软件源有很多,这里选择清华源作为…...
JL-03-Y1 清易易站
产品概述 清易易站是清易电子新研发的一体式气象站,坚持科学化和人文化相结合的设计理念,应用新检测原理研发的传感器观测各类气象参数,采用社会上时尚的工艺理念设计气象站的整体结构,实现了快速观测、无线传输、数据准确、精度较…...
PipeSer管线管网云服务
行业需求 地下管网,作为现代城市不可或缺的基础设施,堪称城市的“地下生命线”。它承载着城市的供水、排水、燃气、电力、通信等重要功能,是确保城市正常运转和居民生活便利的关键所在。将地下管网的复杂布局和运行状态以三维形式直观展现出来…...
kubesphere报错
1.安装过程报错unable to sign certificate: must specify a CommonName [rootnode1 ~]# ./kk init registry -f config-sample.yaml -a kubesphere.tar.gz _ __ _ _ __ | | / / | | | | / / | |/ / _ _| |__ ___| |/…...
【QT5】<总览二> QT信号槽、对象树及样式表
文章目录 前言 一、QT信号与槽 1. 信号槽连接模型 2. 信号槽介绍 3. 自定义信号槽 二、不使用UI文件编程 三、QT的对象树 四、添加资源文件 五、样式表的使用 六、QSS文件的使用 前言 承接【QT5】<总览一> QT环境搭建、快捷键及编程规范。若存…...
2024.05.24 校招 实习 内推 面经
绿*泡*泡VX: neituijunsir 交流*裙 ,内推/实习/校招汇总表格 1、实习丨蔚来2025届实习生招募计划开启(内推) 实习丨蔚来2025届实习生招募计划开启(内推) 2、校招&实习丨联芯集成电路2025届暑期实习…...
如何理解 Java 8 引入的 Lambda 表达式及其使用场景
Lambda表达式是Java 8引入的一项重要特性,它使得编写简洁、可读和高效的代码成为可能。Lambda表达式本质上是一种匿名函数,能够更简洁地表示可传递的代码块,用于简化函数式编程的实现。 一、Lambda表达式概述 1. 什么是Lambda表达式 Lambd…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
2.3 物理层设备
在这个视频中,我们要学习工作在物理层的两种网络设备,分别是中继器和集线器。首先来看中继器。在计算机网络中两个节点之间,需要通过物理传输媒体或者说物理传输介质进行连接。像同轴电缆、双绞线就是典型的传输介质,假设A节点要给…...
前端工具库lodash与lodash-es区别详解
lodash 和 lodash-es 是同一工具库的两个不同版本,核心功能完全一致,主要区别在于模块化格式和优化方式,适合不同的开发环境。以下是详细对比: 1. 模块化格式 lodash 使用 CommonJS 模块格式(require/module.exports&a…...
