Spring Native 文档

Spring Native 文档

概述

Spring Native支持使用GraalVM native-image编译器将Spring应用编译为本地可执行文件。

与Java虚拟机相比,native images可以为许多类型的工作负载提供更加经济、可持续的托管。包括微服务,适合容器和Kubernetes的工作负载。

使用native image可以提供一些关键的优势,例如即时启动、即时峰值性能和较低的内存消耗。

但是native image也会存在一些缺点,需要权衡利弊。GraalVM native项目预计会随着时间还在慢慢改进。构建本地镜像是一个比较重的操作,比普通应用构建要慢的多。本地镜像预热之后运行时优化手段也比较少。最后,它还不如JVM成熟,在不同环境下会有一些不同的表现。

普通的JVM和native image平台最主要的区别在于:

  • 在构建时,需要对你的应用程序从主入口进行静态分析
  • 未使用到的部分在构建时会被删除
  • 反射、资源、动态代理需要配置
  • Classpath在构建时被固定
  • 不支持懒加载:可执行文件中的所有内容在启动时都会被加载到内存中
  • 一部分代码在构建时就会被执行
  • java应用程序某一些方面还有一些限制,不完全支持。

此项目的目标是孵化对 Spring Native(Spring JVM 的替代品)的支持,并提供旨在打包在轻量级容器中的本机部署选项。实际上,此项目最终目标是几乎不加修改的情况下,在这个新平台上支持你的 Spring 应用程序。

模块

Spring Native由以下模块构成:

  • spring-native: 运行 Spring Native 所需的运行时依赖,还提供了Native 提示 API。
  • spring-native-configuration:Spring AOT 插件使用的 Spring 类的配置提示,包括各种 Spring Boot 自动配置。
  • spring-native-docs: 参考指南,asciidoc 格式。
  • spring-native-tools:用于校验镜像构建配置和输出的工具。
  • spring-aot:Maven 和 Gradle 插件共用的 AOT 生成基础设施。
  • spring-aot-test:测试专用的 AOT 生成基础设施。
  • spring-aot-gradle-plugin: 调用 AOT 生成的 Gradle 插件。
  • spring-aot-maven-plugin: 调用 AOT 生成的 Maven 插件。
  • samples:包含各种示例,包含功能的功能演示使用,并用作集成测试。

开始

构建 Spring Boot 原生应用程序主要有两种方式:

开始使用 Buildpack

本节为您提供使用Cloud Native Buildpacks构建 Spring Boot 本机应用程序的实用概述。这是使用RESTful Web 服务入门指南的实用指南

系统要求

应该安装 Docker,有关更多详细信息,请参阅获取 Docker。如果您使用的是 Linux,请将其配置为允许非根用户。

1
您可以运行docker run hello-world(不使用sudo)来检查 Docker 守护程序是否可以按预期访问。查看Maven或Gradle Spring Boot 插件文档以获取更多详细信息。在 MacOS 上,建议将分配给 Docker 的内存至少增加到8GB,并可能添加更多 CPU。有关详细信息,请参阅此Stackoverflow 答案。在 Microsoft Windows 上,确保启用Docker WSL 2 后端以获得更好的性能。

示例项目设置

可以使用以下命令检索完整的“RESTful Web 服务”指南:

1
2
git clone https://github.com/spring-guides/gs-rest-service
cd gs-rest-service/complete
验证 Spring Boot 版本
1
Spring Native 0.12.1 只支持 Spring Boot 2.7.1,如有必要请更改版本。

Maven

1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
<relativePath/>
</parent>

Gradle Groovy

1
2
3
4
plugins {
// ...
id 'org.springframework.boot' version '2.7.1'
}
添加Spring Native 依赖

org.springframework.experimental:spring-native提供本机配置 API @NativeHint,以及将 Spring 应用程序作为本机映像运行所需的其他强制类。您只需要使用 Maven 明确指定它。

maven

1
2
3
4
5
6
7
8
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>0.12.1</version>
</dependency>
</dependencies>

Gradle Groovy

1
// 不需要用Gradle明确添加spring-native依赖,Spring AOT插件会自动添加。
添加 Spring AOT 插件

Spring AOT插件执行改进本机镜像兼容性和占用空间所需的提前转换。( 这些转换也适用于 JVM,因此无论如何都可以应用)

Maven

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot-maven-plugin</artifactId>
<version>0.12.1</version>
<executions>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

Gradle Groovy

1
2
3
4
plugins {
// ...
id 'org.springframework.experimental.aot' version '0.12.1'
}

该插件提供了许多选项来自定义转换,有关更多详细信息,请参阅AOT 生成

启用原生镜像支持

Spring Boot的Cloud Native Buildpacks support让你为你的Spring Boot应用程序构建一个容器。可以使用BP_NATIVE_IMAGE环境变量启用本地镜像构建包,具体如下。

从Spring Native 0.11开始,Liberica Native Image Kit (NIK) is是Buildpacks默认使用的本地镜像编译器。

Maven

1
2
3
4
5
6
7
8
9
10
11
12
<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>

Gradle Groovy

1
2
3
4
5
6
bootBuildImage {
builder = "paketobuildpacks/builder:tiny"
environment = [
"BP_NATIVE_IMAGE" : "true"
]
}

可以使用BP_NATIVE_IMAGE_BUILD_ARGUMENTS环境变量添加额外的本地j镜像参数。

冻结原生镜像版本

默认情况下,native-image版本将由 Buildpacks 自动升级到最新版本。您可以使用特定版本的buildpack显式配置 Spring Boot MavenGradlejava-native-image插件,这将冻结 GraalVM 版本,请参阅相关版本映射。例如,如果你想强制使用原生镜像22.1.0,你可以配置:

Maven

1
2
3
4
5
6
7
8
9
10
11
12
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- ... -->
<image>
<buildpacks>
<buildpack>gcr.io/paketo-buildpacks/java-native-image:7.19.0</buildpack>
</buildpacks>
</image>
</configuration>
</plugin>

Gradle Groovy

1
2
3
4
bootBuildImage {
// ...
buildpacks = ["gcr.io/paketo-buildpacks/java-native-image:7.19.0"]
}
使用替代的本地镜像工具

如果你想把Buildpack使用的默认原生镜像工具包(Liberica NIK)改为其他工具包,你可以明确配置Spring Boot的t Maven 或者 Gradle插件,见相关Buildpack文档。例如,如果你想使用GraalVM CE而不是Liberica NIK,你可以配置。

Maven

1
2
3
4
5
6
7
8
9
10
11
12
13
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- ... -->
<image>
<buildpacks>
<buildpack>gcr.io/paketo-buildpacks/graalvm</buildpack>
<buildpack>gcr.io/paketo-buildpacks/java-native-image</buildpack>
</buildpacks>
</image>
</configuration>
</plugin>

Gradle Groovy

1
2
3
4
bootBuildImage {
// ...
buildpacks = ["gcr.io/paketo-buildpacks/graalvm", "gcr.io/paketo-buildpacks/java-native-image"]
}
Maven库

配置你的构建,包括spring-native 依赖的所需仓库,如下所示。

Maven

1
2
3
4
5
6
7
8
<repositories>
<!-- ... -->
<repository>
<id>spring-milestone</id>;
<name>Spring milestone</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>

Gradle Groovy

1
2
3
4
5
6
pluginManagement {
repositories {
// ...
maven { url 'https://repo.spring.io/milestone' }
}
}

Spring AOT插件同样也需要在Maven的pom.xml文件和Gradle的settings.gradle(.kts)中添加专门的插件库

Maven

1
2
3
4
5
6
7
8
<pluginRepositories>
<!-- ... -->
<pluginRepository>
<id>spring-milestone</id>;
<name>Spring milestone</name>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>

Gradle Groovy

1
2
3
4
5
6
pluginManagement {
repositories {
// ...
maven { url 'https://repo.spring.io/milestone' }
}
}

构建本地应用程序

本地应用程序可以按如下方式构建

1
2
3
4
--Maven--
$ mvn spring-boot:build-image
--Gradle --
$ gradle bootBuildImage

在本地编译过程中,你会看到大量的WARNING: Could not register reflection metadata信息。它们是预期的,并将在未来的版本中被删除,更多细节见#502

使用GraalVM本地镜像编译器构建本地应用程序将创建一个Linux容器。默认情况下,容器映像被安装在本地。

运行本地应用程序

要运行应用程序,你可以按照常用的方式使用docker,如下所示

1
$ docker run --rm -p 8080:8080 rest-service-complete:0.0.1-SNAPSHOT

如果你喜欢docker-compose,你可以在项目的根目录写一个docker-compose.yml,内容如下。

1
2
3
4
5
6
version: '3.1'
services:
rest-service:
image: rest-service-complete:0.0.1-SNAPSHOT
ports:
- "8080:8080"

然后运行

1
$ docker-compose up

启动时间应该低于100ms,相比之下,在JVM上启动大约需要1500ms

现在服务已经启动,访问 localhost:8080/greeting, 你会看到如下内容

1
{"id":1,"content":"Hello, World!"}

开始使用本地构建工具

本节介绍使用GraalVM本地构建工具构建Spring Boot本地应用程序的实用概述。这是一份使用RESTful Web服务入门指南的实用指南。

系统要求

在安装GraalVM本地镜像编译器之前,需要一些先决条件。然后你需要在本地安装原生镜像编译器。本机镜像编译器有不同的发行版本,这里我们主要介绍这两个版本。

Linux和MacOS

要在MacOS或Linux上安装本地镜像编译器,我们建议使用SDKMAN。

  • 安装SDKMAN.
  • 安装GraalVM原生镜像发行版,可以是GraalVM CE(后缀为grl)或Bellsoft Liberica NIK(后缀为nik),这里我们使用Liberica NIK Java 11变体:SDK install java 22.1.r11-nik
  • 确保使用新安装的JDK sdk use java 22.1.r11-nik
  • 运行gu install native-image,将native-image扩展引入JDK

另外,您也可以从 GraalVM 或 Liberica NIK 手动安装构建。如果需要,别忘了适当设置 JAVA_HOME / PATH,并运行 gu install native-image 来引入 native-image 扩展。

Windows

在Windows上,按照 上述说明 安装r GraalVM 或者 Liberica NIK、Visual Studio Build Tools和Windows SDK。由于众所周知的与命令行最大长度有关的Windows限制,确保使用x64 Native Tools Command Prompt而不是常规的Windows命令行来运行Maven或Gradle插件。

项目设置样例

测试用例 “RESTful Web服务 “指南可以使用以下命令下载

1
2
git clone https://github.com/spring-guides/gs-rest-service
cd gs-rest-service/complete
校验 Spring Boot 版本

Spring Native 0.12.2只支持Spring Boot 2.7.7,所以必要时要改变版本。

Maven

1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.7</version>
<relativePath/>
</parent>

Gradle Groovy

1
2
3
4
plugins {
id 'org.springframework.boot' version '2.7.7'
// ...
}
添加Spring Native 依赖

org.springframework.experimental:spring-native提供了像@NativeHint这样的本地配置API,以及将Spring应用作为本地镜像运行所需的其他强制性类。

Maven

1
2
3
4
5
6
7
8
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>0.12.2</version>
</dependency>
</dependencies>

Gradle Groovy

1
// 不需要用Gradle明确添加spring-native依赖,Spring AOT插件会自动添加。
添加Spring AOT插件

Spring AOT 插件可以提前进行必要的转换,以改善本地镜像的兼容性和体积大小

Maven

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot-maven-plugin</artifactId>
<version>0.12.2</version>
<executions>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
<execution>
<id>test-generate</id>
<goals>
<goal>test-generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

Gradle Groovy

1
2
3
4
plugins {
// ...
id 'org.springframework.experimental.aot' version '0.12.2'
}

这个插件提供一系列选项来自定义转换,更多细节见 AOT generation

添加本地构建工具插件

GraalVM 提供了 Gradle 和 Maven 插件可以从你的本地构建种调用本地镜像编译器。下面的例子添加了一个本地配置文件,在打包阶段触发插件。

Maven

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<profiles>
<profile>
<id>native</id>
<dependencies>
<!-- Required with Maven Surefire 2.x -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.13</version>
<extensions>true</extensions>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>build</goal>
</goals>
<phase>package</phase>
</execution>
<execution>
<id>test-native</id>
<goals>
<goal>test</goal>
</goals>
<phase>test</phase>
</execution>
</executions>
<configuration>
<!-- ... -->
</configuration>
</plugin>
<!-- Avoid a clash between Spring Boot repackaging and native-maven-plugin -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>

Gradle Groovy

1
// GraalVM本地构建工具插件被自动应用和配置。

当与Spring AOT一起使用时,默认禁用Native Build Tools Gradle工具链支持,以避免目前与以可靠方式识别具有本地功能的JDK有关的限制。参见 这个相关的Gradle问题

Maven库

配置你的构建,包括spring-native依赖的发布库,以及Maven Central和Gradle的本地构建工具,如下所示。

Maven

1
2
3
4
5
6
7
8
<repositories>
<!-- ... -->
<repository>
<id>spring-milestone</id>;
<name>Spring milestone</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>

Gradle Groovy

1
2
3
4
5
repositories {
// ...
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
}

插件也是如此

Maven

1
2
3
4
5
6
7
8
<pluginRepositories>
<!-- ... -->
<pluginRepository>
<id>spring-milestone</id>;
<name>Spring milestone</name>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>

Gradle Groovy

1
2
3
4
5
6
7
pluginManagement {
repositories {
// ...
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
}
}

构建本地应用程序

本地应用程序可以按如下方式构建

1
2
3
4
--Maven--
$ mvn -Pnative -DskipTests package
--Gradle --
$ gradle nativeCompile

该命令在目标目录下创建一个包含Spring Boot应用程序的本地可执行文件。

运行本地应用程序

要运行应用程序,调用以下内容

1
$ target/gs-rest-service

启动时间应该低于100ms,相比之下,在JVM上启动大约需要1500ms

现在服务已经启动,访问 localhost:8080/greeting, 你会看到如下内容

1
{"id":1,"content":"Hello, World!"}

测试本地应用程序

本地应用程序可按以下方式进行测试。

1
2
3
4
--Maven--
$ mvn -Pnative test
--Gradle --
$ gradle nativeTest

你可以在这里找到关于本地构建工具的更多细节。

支持

Spring Native 现已被 Spring Boot 3 官方原生支持所取代,详情请 参阅相关参考文档。

本节定义了已针对 Spring Native 0.12.2 进行验证的 GraalVM 版本、语言和依赖项,它在本节定义的范围内提供 Beta 支持。如果项目正在使用那些受支持的依赖项,您可以在项目上尝试它,如果出现问题,可以提出错误贡献拉取请求

Beta 支持还意味着将发生重大更改,但将提供并记录迁移路径。

GraalVM

支持 GraalVM 版本 22.1.0,请参阅相关发行说明。影响 Spring 生态系统的 GraalVM 问题在其问题跟踪器上使用标签标识spring

语言

支持 Java 11、Java 17 和 Kotlin 1.5+。

Java 编译器-parameters标志是必需的,因为.class在 JVM 上用作回退机制以检索参数名称的资源通常在本机上不可用。Spring Boot 插件会自动在应用它的模块上配置它,但请确保在不是这种情况时明确配置它(通常在多模块项目中或使用 Kotlin 多平台时)。

工具

支持 Maven 和 Gradle(版本 7 或更高版本)。

Spring Boot

Spring Native 0.12.2 已经通过Spring Boot 2.7.7 测试

需要特殊构建配置的启动器

  • spring-boot-starter-web

    • 目前只支持Tomcat .
    • 服务端开启HTTPS支持需要添加 --enable-https
    • org.apache.tomcat.experimental:tomcat-embed-programmatic 依赖被用于优化占用空间

    Maven

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
    <exclusion>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-core</artifactId>
    </exclusion>
    <exclusion>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-websocket</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    <dependency>
    <groupId>org.apache.tomcat.experimental</groupId>
    <artifactId>tomcat-embed-programmatic</artifactId>
    <version>${tomcat.version}</version>
    </dependency>

    Gradle Groovy

    1
    2
    3
    4
    5
    implementation('org.springframework.boot:spring-boot-starter-web') {
    exclude group: 'org.apache.tomcat.embed', module: 'tomcat-embed-core'
    exclude group: 'org.apache.tomcat.embed', module: 'tomcat-embed-websocket'
    }
    implementation "org.apache.tomcat.experimental:tomcat-embed-programmatic:${dependencyManagement.importedProperties["tomcat.version"]}"
  • spring-boot-starter-actuator

    • 支持WebMvc和WebFlux,以及度量和跟踪基础设施。
    • 当为了优化占用空间不使用指标监控时,排除io.micrometer:micrometer-core。

    Maven

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <exclusions>
    <exclusion>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-core</artifactId>
    </exclusion>
    </exclusions>
    </dependency>

    Gradle Groovy

    1
    2
    3
    implementation('org.springframework.boot:spring-boot-starter-actuator') {
    exclude group: 'io.micrometer', module: 'micrometer-core'
    }
  • spring-boot-starter-test