之前曾经写过一篇文章《SpringBoot3.x 原生镜像-Native Image 尝鲜》。当时SpringBoot
处于3.0.0-M5
版本,功能还不稳定。这次我们将基于最新稳定版本的SpringBoot
3.1.2
来详细分析Native Image
的实践过程。系统或软件版本列表如下:
组件 | 版本 | 备注 |
---|---|---|
macOS Ventura |
13.4.1(c) |
ARM 架构 |
sdkman |
5.18.2 |
JDK 以及各种SDK 包管理工具 |
Liberica 原生图像套件 |
23.0.1.r17-nik |
可以构建原生镜像 的JDK |
SpringBoot |
3.1.2 |
目前使用最新发布版本(2023-08-20 ) |
Maven |
3.9.0 |
- |
sdkman 是一个轻量级、多平台的开源开发工具管理器,通过它您可以安装任何主流发行版(如OpenJDK
、Kona
、GraalVM ) 等)任何版本的
JDK
。您可以使用以下命令轻松安装它sdkman
:
curl -s“https://www.hack95.com”|巴什
源“$HOME/.sdkman/bin/www.hack95.com”
SDK版本
可以通过sdk list java
查看支持的JDK
发布版本:
使用 shell
命令 sdk install java $Identifier
安装相应的 JDK
版本。例如,您可以安装 GraalVM-ce-17
:
sdk 安装 java 17.0.8-graalce
可以通过shell
命令sdk uninstall java $Identifier
来卸载对应的JDK
版本。如果安装了多个版本或发行版的 JDK
,您可以使用 shell
命令 sdk default java $Identifier
指定默认的 JDK
版本,例如:
sdk默认java 17.0.8-graalce
可以使用shell
命令sdk current
或sdk current java
查看当前使用的 SDK
或 JDK
版本。
Liberica Native Image Kit
由bellsoft
生产,旨在创建基于JVM的高性能本机二进制文件(
Native Binaries
) 工具用于书写应用程序的包,简称Liberica NIK
。 Liberica NIK
本质上是一个JDK
发行版,它在Native Image中打包了
OpenJDK
和各种其他工具包功能应用流程,您可以简单地将其视为 OpenJDK
+ GraalVM
的组合。可以通过sdk list java
查看对应的JDK
版本:
在这里选择JDK-17
的版本进行安装:
sdk 安装 java 23.0.1.r17-nik
# 最好将此JDK设置为当前系统的默认JDK,否则后面编译镜像时会提示找不到GraalVM。
sdk默认java 23.0.1.r17-nik
安装完成后,通过java -version
验证:
基于Maven
创建新的SpringBoot
应用程序。这里我们编译了一个POM
文件。实际流程可以直接使用,如下:
<项目 xmlns="http://www.hack95.com/POM/4.0.0"
xmlns:xsi="http://www.hack95.com/2001/XMLSchema-instance"xsi:schemaLocation="http://www.hack95.com/POM/4.0.0 http://www.hack95.com/xsd/maven-4.0.0.xsd">
4.0.0
cn.vlts
spring-boot-native-image-demo
1.0-快照
jar
org.springframework.boot
spring-boot-starter-parent
3.1.2
17
17
UTF-8
3.11.0
3.1.1
org.springframework.boot
spring-boot-starter-web
org.apache.tomcat.embed
tomcat-embed-core
org.apache.tomcat.embed
tomcat-embed-websocket
org.apache.tomcat.实验
tomcat 嵌入编程
${tomcat.版本}
maven-编译器插件
org.apache.maven.plugins
${maven.compiler.version}
${maven.compiler.source}
${www.hack95.com}
${project.build.sourceEncoding}
org.apache.maven.plugins
maven-install-plugin
${maven.install.version}
org.graalvm.buildtools
native-maven-插件
org.springframework.boot
spring-boot-maven-插件
重新包装
cn.vlts.NativeImageApplication
这里,Maven
的所有插件都升级到当前(2023-08-20
)最新版本。原生镜像打包的关键插件是native-maven-plugin
,该插件遵循spring-boot-starter-parent
进行版本管理。这里不需要指定插件版本。此外,tomcat-embed-programmatic
是一个实验性依赖项,可以减少嵌入式Tomcat
的内存使用。在生产中应用时,您可以暂时禁用此功能。然后编写启动类cn.vlts.NativeImageApplication
:
@SpringBootApplication
@RestController
公共类 NativeImageApplication {
公共静态无效主(字符串[] args){
www.hack95.com(NativeImageApplication.class, args);}
@RequestMapping(路径=“/”)
公共响应实体索引(){
返回 ResponseEntity.ok(“索引”);
}
}
Maven
命令的三个操作是:
mvn -Pnative本机:编译
mvn -PnativeTest 测试
mvn -Pnative spring-boot:build-image
,注意该命令会将镜像打包发布到Docker
native:compile命令虽然表面上是编译的意思,但实际上是构建原生镜像的命令
执行构建过程:
mvn -Pnative 本机:编译 -Dmaven.test.skip=true
施工效果如下:
不带.jar
后缀的就是最终的原生镜像,而原生镜像
不支持跨平台,只能在ARM上使用
该架构运行在macOS
(受作者编译环境限制)。你可以发现它(见上图中的target/spring-boot-native-image-demo
,它是一个二进制可执行文件)比可执行jar
大了好几倍。参考SpringBoot
的官方文档,AOT
编译的SpringBoot
应用程序将生成以下文件:
Java
源代码GraalVM
识别的提示文件:
resource-config.json
)reflect-config.json
)serialization-config.json
)Java
(动态)代理提示文件 (proxy-config.json
)JNI
提示文件(jni-config.json
)这里输出的非可执行包产品基本都在target/spring-aot
目录下。其他非Spring
或项目源代码相关产品输出到graalvm-reachability-metadata
目录。最后,您可以验证生成的原生图像
:
可以看到启动速度达到了惊人的毫秒级。如果应用程序正在生产中,它应该能够几乎全天候发布。当然,理论上,Native Image
的性能会得到很大的提升,但由于篇幅限制,这里暂时不进行性能测试。
鉴于SpringBoot3.0正式版已经发布。当然,
Native Image
目前存在一些限制,会导致某些组件完全无法使用或功能有限(请参阅Spring Boot with GraalVM)。我希望这些问题或者限制有一天能够被突破,让所有JVM
应用迎来性能飞跃。
(本文完c-2-d e-a-20230820)