传统的 Spring 应用程序都是必须依赖于 Java 虚拟机(JVM)运行的,Spring Native 的诞生就是无需 JVM,它提供了另外一种运行和部署 Spring 应用的方式(目前只支持 Java 和 Kotlin),通过 GraalVM 将 Spring 应用程序编译成原生镜像。
# Spring Native 特点
1、无需 JVM 环境, Spring Native 应用程序可以作为一个可执行文件独立部署;
2、应用即时启动,一般情况下应用启动时间 < 100ms;
3、即时的峰值性能;
4、更少的内存消耗;
# Spring Native 缺点
Spring Native 应用启动那么快也是有代价的,和 JVM 应用相比:
1、构建更笨重、构建时间更长;
2、更少的运行时优化;
3、很多 Java 功能受限;
4、很多特性还很不成熟;
# Spring Native 应用场景
1、Spring Cloud 无服务器化(Serverless);
2、以更廉价持久的方式运行 Spring 微服务;
3、非常适合 Kubernetes 平台,如:VMware Tanzu;
4、为 Spring 应用创建更佳的容器镜像;
#Spring Native 和 JVM 的区别
1、Spring Native 构建时会进行应用程序静态分析;
2、Spring Native 构建时会移除未被使用的组件;
3、Spring Native 反射、资源、动态代理需要配置化;
4、Spring Native 构建时的 classpath 是固定不变的;
5、Spring Native 没有类延迟加载,可执行文件包含所有内容都在启动时加载到内存;
6、Spring Native 构建时会运行一些代码;
7、Spring Native 对于 Java 应用程序还存在一些局限性;
#GraalVM 简介
Spring Native 的核心就是 Oracle 的黑科技:GraalVM。
GraalVM 是一个由 Oracle 开发的全栈通用虚拟机,拥有高性能、跨语言交互等逆天特性,不仅支持了 Java、Scala、Groovy、Kotlin 等基于 JVM 的语言,以及 C、C++ 等基于 LLVM 的语言,还支持其他像 JavaScript、Ruby、Python 和 R 语言等,可提高多种语言的运行速度和吞吐量。
首先用命令行试试
到https://github.com/graalvm/graalvm-ce-builds/releases
下载 graalvm 来代替jdk
我下载的是
解压缩配置环境变量
export GRAALVM_HOME=/home/qzc/program/graalvm-ce-java8-21.0.0.2
export JAVA_HOME=$GRAALVM_HOME
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=.:$JAVA_HOME/bin:$PATH:$MAVEN_HOME/bin:$GRAALVM_HOME/bin
然后手动下载 https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0.2/native-image-installable-svm-java8-linux-amd64-21.0.0.2.jar
将native这个jar放到graalvm的bin目录下离线安装
gu -L install native-image-installable-svm-java8-linux-amd64-21.0.0.2.jar
然后就可以用native-image命令了
编译java文件 javac HelloWorld.java
将class文件编译为可执行文件 native-image HelloWorld
就可以直接执行HelloWorld 了,不需要jvm了
试过稍微复杂的springboot工程,native-image -jar ./target/spring-boot-native-1.0.jar
会出现不能找到main函数入口
还是继续用maven插件自动编译成docker镜像吧
到https://start.spring.io/创建工程,依赖加入
Spring Native 和 Spring Web
生成工程后,手动创建一个 web服务文件
@RestController
public class WebmvcController {
@GetMapping("/")
public String foo() {
return "Hello GraalVm from native-image: /hello/name";
}
@GetMapping("/hello/{name}")
public String foo(@PathVariable String name) {
return "Hello " + name;
}
}
在ide里springboot应用可以运行,打包jar也正常
mvn package -DskipTests 跳过单元测试,但是会继续编译
mvn package -Dmaven.test.skip=true 不执行测试用例,也不编译测试用例类。
不构建镜像,这个时候可以直接用jar了
java -jar ./target/demo-0.1.jar
构建docker镜像耗时比较长
./mvnw spring-boot:build-image
每次构建都要从https://github.com下载graalvm 和 native,造成docker里缓存很多失败文件,几次下来硬盘可能就塞满了,所以必要时清理docker缓存
docker system prune -a -f?
docker system df 清完之后看一下
如果成功构建,可以用命令
docker run --rm -p 8080:8080 demo:0.1
或docker-compose.yml文件启动
version: '3'
services:
demonative:
image: demo:0.1
container_name: demonative
restart: always
ports:
- 8080:8080
启动命令 :
docker-compose up -d
停止
docker-compose down
大概率构建会失败,因为下载graalvm300多m可能会失败,即便成功,再下载native这个几M点jar也会失败,这个现在还是beta版,将来正式推广有国内镜像的话也许就不至于这么费事了,最好是下载过一次。能够配置一下复用不需要每次下载才有意义。