spring boot 3 已经出来一段时间了,官方也把 GraalVM native 作为 sp3 的一个重大的功能。
那什么是 GraalVM 呢?#
从名字就可以看出来 GraalVM 是一个虚拟机,它的主要目标就是提升 java 应用程序的性能,并且消耗更少的资源。
它在 java HotSpot JVM 的基础上添加了 JIT 编译器和 AOT 来实现将应用编译成为本地可执行文件。除了 java 之外,GraalVM 还支持 JavaScript、Ruby、Python 等多种编程语言。
通俗点讲,GraalVM 能够让 Java 或其它语言用其解释器编译为二进制程序。用 spring boot 3 框架编写的 Java 程序被转换后,启动速度更快,内存占用更小,到达最佳性能用时更短。
为什么需要 GraalVM?#
为什么 Java 这么重视 GraalVM 呢?
众所周知,Java 作为一门老语言,渐渐跟不上新兴的技术与潮流。虽然 JDK 一直在更新,但还是受限于历史包袱的原因,船大难掉头。
这其中云原生,serverless,容器化这些新潮玩意就不讲武德猛踹 Java 那条坏腿。虽然还没到踹到半死不活的地步,但这是未来大势,不可阻挡。
关于 serverless 的思考#
对于 serverless (无服务器计算) 的 Providers (云服务器商) 而言,更小的内存占用,更快的启动速度无疑是降低成本的必然选择。
对于 Consumer (消费者 - 企业) 而言,省去了购买服务器及运维的钱,又支持按量计费,无疑非常有吸引力。
另一方面,AI 大模型对行业重新洗牌,但有能力训练、部署、迭代的只有大公司,而又可以提供大模型能力的只有云服务器商。那 serverless 就几乎只能成为中小公司对接 AI 的最佳选择。
安装 GraalVM#
在官方网站下载并解压,完成后需配置环境变量
可以使用官方的配置方式
#注意修改下面的地址为你本地解压的地址
setx /M PATH "C:\Program Files\Java\graalvm-ce-java11-20.3.0\bin;%PATH%"
setx /M JAVA_HOME "C:\Program Files\Java\graalvm-ce-java11-20.3.0"
也可以直接配置环境变量
win
+ i
进入设置 --- 高级系统设置 --- 环境变量,增加如下的配置
GRAALVM_HOME :解压的路径
JAVA_HOME :解压的路径
然后在path里面配置
%GRAALVM_HOME%\bin
%JAVA_HOME%\bin
使用 cmd 的 java -version
命令查看版本,如果有 GraalVM 字样表示成功
安装编译环境#
要将 Java 通过 GraalVM 编译成二进制,需要安装 C++ 环境
以下是通过Visual Studio安装相关环境的方法,你也可以查看官方教程
如果你是 Windows 11,不要使用官方教程里面的 Visual Studio 2019,而应该使用最新版
安装下面的组件
创建 spring boot 3 项目#
使用 idea 创建
JDK 要选择 GraalVM 的,Java 版本要选择 17 及以上的
选择 spring boot 3.0 以上版本,添加 GraalVM Native Support 和 Web 依赖
创建完成后 maven 文件中应有如下插件
完成后新建一个 controller 编写一个简单的接口
@RestController
@RequestMapping("user")
public class UserController {
@GetMapping("test")
public String test(){
return "hello world";
}
编译及构建#
代码写完了,我们就要编译了
打开 Visual Studio Build Tools x64 Native Tools Command Prompt for VS 2022
x64、x86 都是可以的,然后进入项目目录
使用 mvn -PnativeTest test
进行编译测试
没有错误后使用 mvn native:build
进行构建,完成后会在项目目录生成一个 exe 文件
可以看到,构建后的文件还是很大的,这是因为在构建过程中打包了一些依赖
其中大约 50M 是代码的体积,这一部分还包含了一个 java.base
30M 是镜像的堆体积,剩下的是其它数据
启动 exe 文件,发现速度可以说是光速了
现有不足#
GraalVM 可以说是一个非常有意思的东西,它是 Java 对云原生的一次勇敢尝试,它解决了 Java 的重大弊病,但同时也带了致命的问题。
Java 中的动态调用支持引入各种依赖,并在调用时进行指向,而 GraalVM Native 使用的 AOP (提前编译) 是基于静态代码可达分析。通俗点讲就是 Java 编译时不知道你有什么用,但在调用时就可以找到了,而 GraalVM 在编译时则一定要指定你是谁,你有什么用。
GraalVM 牺牲了编译耗时,优化了启动耗时。这当然是正确的,但它也无法动态调用了。
尽管其提供了使用反射解决的方法,但目前仍非常复杂
我尝试引入 mybatis 的依赖,但并未使用,测试编译就并未通过。
在 spring boot3 中使用 native image
Using GraalVM and Native Image on Windows 10