本文记录了使用native-image编译SpringBoot3.0.3的过程及遇到的问题。其中一些问题也是网上很多朋友遇到,我在实际操作的过程也遇到过同样的问题,在此做一记录。
目录
一、编译环境准备
1.1 安装GraalVM
它在java HotSpot JVM的基础上添加了JIT编译器和AOT来实现将应用编译成为本地可执行文件。除了java之外,GraalVM还支持JavaScript、Ruby、Python等多种编程语言。
GraalVM下载地址:https://www.oracle.com/downloads/graalvm-downloads.html。下载的时候选择对应的平台和版本。
GraalVM跟JDK一样也有两个版本,社区版和企业版本,大家可以根据需要自行选择。
如果下载的zip压缩文件,选择一个目录将它解压即可。
1.2 安装native-image
- 方法1 : 控制台输入命令 gu install native-image即可,下载速度贼慢
- 方法2:在github上下载对应版本的native-image安装包进行本地安装
Release GraalVM Community Edition 22.3.0 · graalvm/graalvm-ce-builds (github.com)
控制台输入命令 gu install -L 你的下载位置
安装成功,控制台输入gu list如图所示
环境变量配置:
JAVA_HOME = GraalVM的的根目录
PATH = %JAVA_HOME%\bin
1.3 IDE设置
打开项目的Project Settings,SDK--->Edit---->Add SDK 选择GraalVM。
Edit Configurations
设置Build and run 的JRE为GraalVM-17
1.4 Visual Studio 2022
由于Windows相关的命令行最大长度限制,所以需要使用x64 Native Tools Command Prompt而不是常规的Windows命令来运行maven或者Gradle插件。
安装好后需要配置Visual Studio的环境变量。
mvn -Pnative native:compile
1.5 pom.xml文件
<build> <plugins> <plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build
native-maven-plugin 默认为最新版本:0.9.20
二、使用native-image工具本地编译
1、打开X64 Native Tools Command Propmt窗口执行:
mvn -Pnative native:compile
执行过程中出现下面错误信息:
Execution of E:\tools\graalvm-ce-java17-22.3.1\bin\native-image.cmd @target\tmp\native-image-2154084464642699530.args returned non-zero result
如下图:
根据错误提示我们查看并修改
F:\myworkspace\demo-test\demo\target\native-image-2154084464642699530.args
文件将里面的所有\\路径全局替换为/路径符号。
替换前:
替换后:
为什么将“\\”替换为“/”就可以成功执行,此处应该是 native-maven-plugin(0.9.20) 版本导致的,0.9.19版本也有同样的问题,在linux下应该没有此问题。
然后我们手动执行刚才报错的命令 (重要,也就是原来一步完成的任务,现在需要两步完成)
native-image @target\tmp\native-image-2154084464642699530.args
此处我们也可以将args文件中的参数粘贴出来作为native-image 后面的参数,不需要替换路径,只需要将相关参数合并成单行命令执行也能成功,说明native-image通过vcvars64.bat脚本执行后是支持window的路径\\格式的)
等价于
执行完毕结果
本文参考:
SpringBoot3 Graalvm Native-Image尝鲜_Zyp168168的博客-CSDN博客
三、AOT技术
GraalVM Native Images是一个利用AOT(Ahead-of-Time)技术把java程序直接编译成可执行程序的编译工具,编译出来的程序在运行时不再依赖JRE,同时启动速度快,资源消耗低,这对传统java程序来说都是极大的优势。
同时云原生应用来说,GraalVM Native Images编译生成的程序体积很小,非常适合云原生环境,目前由于传统java程序生成的镜像中需要包含一个体积很大的JRE或JDK而经常被人诟病。Spring Boot从3.0版本开始支持AOT技术。
3.1 AOT与JIT
- 在程序运行前编译,可以避免在运行时的编译性能消耗和内存消耗
- 可以在程序运行初期就达到最高性能
- 可以显著的加快程序的启动
3.2 缺点
- 程序运行时动态调整的资源无法直接使用,例如反射、动态代理等,需要在代码中通过Hint为编译器指定
- 应用的classpath在编译后就固定了,不能动态调整
- 类不会延迟加载(lazy loading),应用启动时一次性加载完成
- 部分java切面(AOP)技术不支持
- 编译时间长
- 牺牲了跨平台的的优势
- 将提前编译的内容保存会占用更多的外存
3.3 JIT优点
顺便说一下JIT
- 可以根据当前硬件情况实时编译生成最优机器指令(ps. AOT也可以做到,在用户使用是使用字节码根据机器情况在做一次编译)
- 可以根据当前程序的运行情况生成最优的机器指令序列
- 当程序需要支持动态链接时,只能使用JIT
- 可以根据进程中内存的实际情况调整代码,使内存能够更充分的利用
3.4 JIT缺点
- 编译需要占用运行时资源,会导致进程卡顿
- 由于编译时间需要占用运行时间,对于某些代码的编译优化不能完全支持,需要在程序流畅和编译时间之间做权衡
- 在编译准备和识别频繁使用的方法需要占用时间,使得初始编译不能达到最高性能
四、单元测试
传统的Spring Boot3单元测试技术仍然可以使用。需要注意的是 Spring Native不支持JUnit4,需要使用JUnit5。