1、SpringNative
springboot3于2022年11月25日发布,强制要求jdk17,并拥有很多新特性。其中最重要的就是spring-native。
spring-native实际上是结合Oracle公司的 graalvm ,将java程序编译成二进制机器码,进行运行。
我们知道java是一门半编译半解释的语言
- 编译:javac编译的时候会将部分直接调用c++的代码(native包调用),编译成jit代码缓存(jvm的元空间内)进行调用,而代码缓存是直接被编译成二进制机器码的。
- 解释:结合了java虚拟机,将class文件放入java虚拟机进行解释运行。
java热门的原因是由java虚拟机赋予的:跨平台性,运行时创建对象(反射)。而在云原生遍地开花的时代,跨平台性已经被类似docker这种容器化技术所取代。而在云环境下,为了跑java应用还需要在虚拟容器中安装java运行环境,非常的麻烦。因此,将java编译成为二进制机器码,直接调用指令集成为我们不可不重视的功能。
表现在操作系统中就是,比如在windows下,编译后会直接打包成一个 exe
文件,我们直接双击运行就可以了。那么发给其他任何一个没有安装java环境(jdk)的人,都可以直接运行起来。
我们来对比一下新 graalvm
和 hotspot
的区别:
名称 | graalvm | hotspot |
---|---|---|
原理 | 编译成二进制机器码 | 半解释半编译 |
环境 | 不需要,直接操作系统下运行 | 需要安装java(jdk)环境 |
运行内存占用 | 非常小(70mb) | 比较大(300mb,要运行jvm) |
启动速度 | 微秒级(0.03ms) | 秒级(5600ms) |
编译速度 | 非常慢(300s) | 非常快(12s) |
遗留问题
前面我们提到了AOT编译的好处,实际上jvm另外一个优点就是动态字节码。Java 过去之所以没有全面编译,并非占用内存增加和启动时间变慢,GraalVM Native Image 也需要编程很长时间,消耗很大的内存。实际上,GraalVM 是无法解决这个问题的,尤其是 JVM 字节码动态性,比如 CGLIB 动态生成或者 Java 反射的不确定性。其实,对于大多数业务代码,GraalVM AoT 编译器基本上可以完成静态化,主要是在框架代码上,有些麻烦,比如 Spring Stack,所以 Spring Native 做了大量的辅助工作,也帮助 GraalVM 提升稳定性,然而部分代码还需要自行声明。
参考
CSDN-SpringNative GraalVM 打包 SpringBoot 为 Windows 的 exe 应用程序
CSDN-Default native-compiler executable ‘cl.exe‘ not found via environment variable PATH
bilibili-【Java前沿】Spring6为什么强制要求JDK17?AOT到底是什么!技术专家必看!-极海Channel
1.1、使用graalvm
想要体验graalvm,我们只需要安装对应环境即可。我们知道graalvm会把java编译成为操作系统认知可运行的二进制文件,因此对应的编译工具是需要的。苹果和linux自带编译工具,因此不需要转其他东西,windows需要安装visualstudio来确保能编译成对应的可执行文件。
使用graalvm步骤如下:
- 安装graalvm ,配置环境变量,
graalvm
目录和graalvm/bin
目录。 - 安装对应操作系统内核的编译环境(可选,windows需要安装visualstudio)
- 使用编译环境编译java的class文件,也就是java编译后文件
1.2、win使用graalvm
我们尝试在windows下使用graalvm编译java程序。
1.3.1、安装GraalVM
GraalVM自带jdk,因此安装后就不需要额外安装jdk。由于springboot强制要求jdk17,因此GraalVM也建议安装代jdk17或以上的。
安装完成之后解压,放在你配环境的位置。
然后配置环境变量,请注意,环境变量需要将GraalVM目录以及GraalVM目录下的bean目录放在path中。我们采用 JAVA_HOME
的方法。
path变量
当然,我们可以测试一下是否成功,打开cmd,输入两个命令
# 查看jdk版本
java -version
# gu命令
gu
gu命令是GraalVM内置的命令工具,如果你输入之后未找到命令,那就是GraalVM安装目录下的bin目录没有添加进环境变量的path中
1.3.2、安装VisualStudio
前面我们有提到过,windows并不自带内核可执行文件编译环境,因此需要安装,windows编译环境就是VisualStudio内的c++环境。
我们运行下载下来的 VisualStudioSetup
,必要的安装一下2个程序
1、 MSVC v143 - VS 2022 c++ x64/x86生成工具
# 根据你的jdk版本来选,jdk11需要MSVC v140 2015、jdk15需要MSVC v141 2017、jdk17需要MSVC v142 2019、jdk21需要MSVC v143 2022。当然他们向下兼容,如果你运行中出现了问题,尝试更换对应的版本。
2、Windows 11 SDK
# 根据你的windows版本选择,如果说windows10就选择win10
此外,我们需要重启电脑,假如你能搜索到并可以打开一个叫 x64 Native Tools Command Prompt for VS 2022
的运行窗口,那么就安装成功了。
一定是x64的,如果是x86的后续会编译失败
记住这个窗口,非常重要,编译都需要在这个窗口中进行
在后需编译中可能出现报错:Default native-compiler executable ‘cl.exe‘ not found via environment variable PATH
因此,我们强烈建议你把 cl.exe
的路径添加在path中,例路径如下: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.16.27023\bin\HostX64\x64
路径可能会出现改动,如果不在 Program Files (x86)
路径下就是在 Program Files
下,也有其他路径可能出现问题请你多找一找。
我的路径就是: C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\bin\Hostx64\x64
你要将这个路径添加进环境变量的 path
下
我们可以随意打开一个cmd,执行 cl.exe
命令,如果执行成功就说明环境变量添加成功
1.3.3、安装aot编译器native-image
我们之前已经将 GraalVM
添加入环境变量,使用 gu
命令可以安装编译器native-image
- 一定要打开之前的
x64 Native Tools Command Prompt for VS 2022
窗口,不能是普通cmd窗口,否则会执行失败 - 执行
gu install native-image
命令
注意:
- 一定是截图窗口
- 一定是x64版本
- gu命令找不到的原因是graalvm目录下的bin目录没有配置环境变量
1.3.4、使用graalvm编译普通java程序
我们已经安装完了必要环境,具体步骤如下:
- 打开之前的
x64 Native Tools Command Prompt for VS 2022
窗口 - 切换到java程序所在的目录
- 将java程序使用
javac
命令编译成class文件 - 使用native-image编译javac编译过的文件
1、我们编写一个普通的java程序
public class Hello {
public static void main(String[] args) {
System.out.println("hello graalVM");
System.out.println("hello spring native");
}
}
2、打开之前的 x64 Native Tools Command Prompt for VS 2022
窗口,切换java程序所在的目录,并执行 javac
命令将java文件编译
编译过后会生成一个 .class
文件
3、使用native-image编译编译过的文件,我的命令如下:native-image Hello
4.编译过后我们会获得一个可以直接执行的文件,在windows中就是 .exe
文件。我们可以直接运行起来
1.3.5、步骤总结
我们回顾一下使用的步骤
- 将java源文件使用
javac
编译成class文件
class文件
再编译成能够直接运行在操作系统上的二进制机器码,也就是当前操作系统内核直接运行的指令集- windows下会直接编译成
exe
文件直接运行即可
需要注意的是,比较麻烦的是在编译的过程需要安装运行环境,而在 windows 中就是 c++ 环境 vs 了。
1.3、springNative使用
spring-native在springboot3.0版本发布之后,也随之加入进来。前面我们有了解到,GraalVM本身就是吧javac编译的源文件直接打包编译成操作系统可以直接运行的文件,因此,springboot同样是编译之后再用GraalVM编译一遍即可。这个功能被集成到了maven的插件 native-maven-plugin
上。
我们可以大致了解以下步骤:
- 加入maven的插件
native-maven-plugin
- 使用windows的c++开发环境进行编译,也就是
x64 Native Tools Command Prompt for VS 2022
窗口
1.3.1、springboot3.0体验
注意:springboot3.0要求jdk不低于jdk17
1、首先我们需要快速创建一个springboot3.0版本的项目
2、添加spring-native插件,刷新maven之后就能看见插件
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
springboot3.0配置文件中已经添加了插件依赖,因此我们只要声明就行了,不需要指定版本。
插件的作用就是编译java并且使用操作系统的可执行内核程序进行编译。
3、使用 x64 Native Tools Command Prompt for VS 2022
窗口进行编译
在mac或者linux中是可以直接使用插件的 compile
功能进行编译,但是windows不行,必须使用这个窗口。需要跳转到项目目录中,进行maven指令编译。
我们需要先切换到项目目录下,windows下使用: cd /d [目标目录]
调用插件 native:compile
的指令为:mvn -Pnative native:compile
编译完成之后,会在 target
目录下生成一个 项目名.exe
文件,我们可以直接运行看效果