Spring Native 官网地址:https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/
什么是spring native
Spring Native 可以通过 GraalVM 将 Spring 应用程序编译成原生镜像,提供了一种新的方式来部署 Spring 应用。
这个项目的目标是寻找 Spring JVM 的替代方案,提供一个能将应用程序打包,并运行在轻量级容器的方案。期望能够在 Spring Native 中支持所有的 Spring 应用程序。
spring native 的有优缺点
优点:
- 编译出来的原生 Spring 应用可以作为一个独立的可执行文件进行部署(不需要安装 JVM)
- 启动快(一般小于 100 毫秒)
- 占用内存小
缺点:
- GraalVM在打包的配置要求上较高
- 比 JVM 构建时间更长
- 对于使用了反射的项目来说,需要在使用GraalVm构建native image前需要通过配置列出反射可见的所有类型
原生镜像和常规 JVM 的区别
- 在构建时会从主入口点,静态分析应用程序
- 在构建时会移除未使用的代码
- 需要配置反射、动态代理等
- classpath 在构建时就已经确定
- 没有类延迟加载:可执行文件中所有的内容都会在启动时加载到内存中
- 在构建时就运行了一些代码
- 构建原生镜像还存在一些 局限性
JVM 的程序运行时间长,是因为存在虚拟机的初始化和类加载过程,如果将字节码直接编译成原生代码,则可以彻底解决这些问题。同时因为没有即时编译器在运行时编译,所有代码都在编译期编译和优化。因为少了 Java 虚拟机、即时编译器这些额外组件,原生程序也能够省去它们原本消耗的内存资源和镜像体积。
了解GraalVM
GraalVM 是一个高性能的多语言运行时环境。设计目的是能够提高用 Java 和其他 JVM 语言编写的应用程序的执行速度,同时还为 JavaScript、Ruby、Python 和许多其他流行语言提供运行时。GraalVM 的多语言能力使得在一个应用程序中混合使用多种编程语言成为可能,同时消除了不同语言间互相调用的成本。
GraalVM 下的 Java 微服务
- 启动时间更快
- 内存占用更少
构建 Spring Boot native 应用程序有 2 种方式
- 使用 Spring Boot Buildpacks support 构建一个包含本地可执行文件的轻量级容器。(要求java11+)
- 使用 the GraalVM native image Maven plugin support 构建一个本地可执行文件。(要求SpringBoot3.0+,java17+)
Spring Native 所遇到的问题
对于反射,需要用户在编译期,通过配置文件或编译器参数的形式,明确告知编译器程序代码中哪些方法只通过反射来访问的。
用户往往不知道动态生成字节码的具体信息,这些只能由程序去做妥协。默认情况下,每一个 Spring 管理的 Bean 都要用到 CGLib。从 Spring Framework 5.2(SpringBoot与SpringFramework对应关系) 开始增加了@proxyBeanMethods 注解来排除对 CGLib 的依赖,仅使用标准的动态代理去增强类。
成功通过Spring Boot Buildpacks support 构建一个包含本地可执行文件的轻量级容器的关键
- java jdk 要求版本 jdk-11.0.18+
- 安装本地 maven 并配置好环境 版本不要太低
- 安装Windows下docker 并配置好环境 https://blog.csdn.net/qubernet/article/details/125593666
- maven 配置文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>spring-native</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>spring-native</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.1</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding> <java.version>11</java.version> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <spring-native.version>0.11.0</spring-native.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.experimental</groupId> <artifactId>spring-native</artifactId> <version>${spring-native.version}</version> </dependency> </dependencies> <build> <plugins> <!--Spring AOT 插件执行代码的提前转换,用以修复 native image 的兼容性--> <plugin> <groupId>org.springframework.experimental</groupId> <artifactId>spring-aot-maven-plugin</artifactId> <version>${spring-native.version}</version> <executions> <execution> <id>test-generate</id> <goals> <goal>test-generate</goal> </goals> </execution> <execution> <id>generate</id> <goals> <goal>generate</goal> </goals> </execution> </executions> </plugin> <!--Spring Boot Buildpacks support 可以将 Spring Boot 应用程序打包成一个容器--> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <image> <builder>paketobuildpacks/builder:tiny</builder> <env> <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE> </env> </image> </configuration> </plugin> </plugins> </build> <repositories> <!--仓库地址 --> <repository> <id>spring-release</id> <name>Spring release</name> <url>https://repo.spring.io/release</url> </repository> </repositories> <pluginRepositories> <!--插件仓库地址 --> <pluginRepository> <id>spring-release</id> <name>Spring release</name> <url>https://repo.spring.io/release</url> </pluginRepository> </pluginRepositories> </project>
- 开始通过mvn构建镜像前先把梯子打开
- 开始构建
mvn spring-boot:build-image
第一次构建时间比较慢长(大约10分钟以上),之后再构建大约3分钟左右 - 构建成功后就可以直接启动
docker run --rm -p 8080:8080 镜像名称
删除镜像docker rmi -f 镜像ID
温馨提示
maven demo项目https://github.com/enChenging/spring-native
gradle demo项目https://github.com/enChenging/spring-native-gradle-simple