开发你的第一个 GraalVM Native 应用

构建 Spring Boot native image 应用有两种主要方式:

提示:开始一个新的 native Spring Boot 项目最简单的方法是访问 start.spring.io,添加 GraalVM Native Support 依赖并生成项目。 包含的 HELP.md 文件将提供入门提示。

示例应用

我们需要一个示例应用来创建我们的 native image。 对于我们的目的来说,开发您的第一个 Spring Boot 应用程序 部分中介绍的简单 "Hello World!" Web 应用就足够了。

回顾一下,我们的主应用代码如下:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class MyApplication {

	@RequestMapping("/")
	String home() {
		return "Hello World!";
	}

	public static void main(String[] args) {
		SpringApplication.run(MyApplication.class, args);
	}

}

这个应用使用了 Spring MVC 和嵌入式 Tomcat,两者都经过测试并验证可以在 GraalVM native image 中工作。

使用 Buildpacks 构建 Native Image

Spring Boot 支持使用 Cloud Native Buildpacks (CNB) 与 Maven 和 Gradle 的集成以及 Paketo Java Native Image buildpack 来构建包含 native 可执行文件的 Docker 镜像。 这意味着你只需输入一个命令就可以快速获得一个合理的镜像到本地运行的 Docker daemon 中。 生成的镜像不包含 JVM,而是静态编译的 native image。 这导致镜像更小。

注意:用于镜像的 CNB builder 是 paketobuildpacks/builder-jammy-java-tiny:latest。 它占用空间小,攻击面减少。它不包含 shell,并且包含减少的系统库集。 如果需要更多工具,可以使用 paketobuildpacks/builder-jammy-base:latestpaketobuildpacks/builder-jammy-full:latest

系统要求

需要安装 Docker。有关更多详细信息,请参阅 Get Docker。 如果你在 Linux 上,请 配置它以允许非 root 用户

注意:你可以运行 docker run hello-world(不带 sudo)来检查 Docker daemon 是否按预期可达。 有关更多详细信息,请查看 MavenGradle Spring Boot 插件文档。

提示:在 macOS 上,建议将分配给 Docker 的内存增加到至少 8GB,并可能添加更多 CPU。 有关更多详细信息,请参阅此 Stack Overflow 回答。 在 Microsoft Windows 上,确保启用 Docker WSL 2 backend 以获得更好的性能。

使用 Maven

要使用 Maven 构建 native image 容器,你应该确保你的 pom.xml 文件使用 spring-boot-starter-parentorg.graalvm.buildtools:native-maven-plugin。 你应该有一个看起来像这样的 <parent> 部分:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>3.4.6</version>
</parent>

你还应该在 <build> <plugins> 部分中添加以下内容:

<plugin>
	<groupId>org.graalvm.buildtools</groupId>
	<artifactId>native-maven-plugin</artifactId>
</plugin>

spring-boot-starter-parent 声明了一个 native profile,它配置了创建 native image 所需的执行。 你可以使用命令行上的 -P 标志来激活 profiles。

提示:如果你不想使用 spring-boot-starter-parent,你需要为 Spring Boot 插件的 process-aot 目标和 Native Build Tools 插件的 add-reachability-metadata 目标配置执行。

要构建镜像,你可以在激活 native profile 的情况下运行 spring-boot:build-image 目标:

$ mvn -Pnative spring-boot:build-image

使用 Gradle

当应用 GraalVM Native Image 插件时,Spring Boot Gradle 插件会自动配置 AOT 任务。 你应该检查你的 Gradle 构建是否包含包含 org.graalvm.buildtools.nativeplugins 块。

只要应用了 org.graalvm.buildtools.native 插件,bootBuildImage 任务就会生成 native image 而不是 JVM 镜像。 你可以使用以下命令运行任务:

$ gradle bootBuildImage

运行示例

一旦你运行了适当的构建命令,Docker 镜像应该就可用。 你可以使用 docker run 启动你的应用:

$ docker run --rm -p 8080:8080 docker.io/library/myproject:0.0.1-SNAPSHOT

你应该看到类似于以下的输出:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v{version-spring-boot})
....... . . .
....... . . . (log output here)
....... . . .
........ Started MyApplication in 0.08 seconds (process running for 0.095)

注意:启动时间因机器而异,但它应该比在 JVM 上运行的 Spring Boot 应用快得多。

如果你在 Web 浏览器中打开 localhost:8080,你应该看到以下输出:

Hello World!

要优雅地退出应用,请按 ctrl-c

使用 Native Build Tools 构建 Native Image

如果你想在不使用 Docker 的情况下直接生成 native 可执行文件,你可以使用 GraalVM Native Build Tools。 Native Build Tools 是 GraalVM 为 Maven 和 Gradle 提供的插件。 你可以使用它们执行各种 GraalVM 任务,包括生成 native image。

先决条件

要使用 Native Build Tools 构建 native image,你需要在机器上安装 GraalVM 发行版。 你可以从 Liberica Native Image Kit 页面手动下载,或者使用像 SDKMAN! 这样的下载管理器。

Linux 和 macOS

要在 macOS 或 Linux 上安装 native image 编译器,我们推荐使用 SDKMAN!。 从 sdkman.io 获取 SDKMAN! 并使用以下命令安装 Liberica GraalVM 发行版:

$ sdk install java 22.3.r17-nik
$ sdk use java 22.3.r17-nik

通过检查 java -version 的输出来验证是否配置了正确的版本:

$ java -version
openjdk version "17.0.5" 2022-10-18 LTS
OpenJDK Runtime Environment GraalVM 22.3.0 (build 17.0.5+8-LTS)
OpenJDK 64-Bit Server VM GraalVM 22.3.0 (build 17.0.5+8-LTS, mixed mode)

Windows

在 Windows 上,按照 这些说明安装 GraalVMLiberica Native Image Kit 版本 22.3、Visual Studio Build Tools 和 Windows SDK。 由于 Windows 相关的命令行最大长度,确保使用 x64 Native Tools Command Prompt 而不是常规的 Windows 命令行来运行 Maven 或 Gradle 插件。

使用 Maven

buildpacks 支持一样,你需要确保使用 spring-boot-starter-parent 以继承 native profile,并且使用 org.graalvm.buildtools:native-maven-plugin 插件。

在激活 native profile 的情况下,你可以调用 native:compile 目标来触发 native-image 编译:

$ mvn -Pnative native:compile

native image 可执行文件可以在 target 目录中找到。

使用 Gradle

当 Native Build Tools Gradle 插件应用到你的项目时,Spring Boot Gradle 插件将自动触发 Spring AOT 引擎。 任务依赖关系会自动配置,因此你可以直接运行标准的 nativeCompile 任务来生成 native image:

$ gradle nativeCompile

native image 可执行文件可以在 build/native/nativeCompile 目录中找到。

运行示例

此时,你的应用应该可以工作了。你现在可以直接运行它来启动应用:

  • Maven

  • Gradle

$ target/myproject
$ build/native/nativeCompile/myproject

你应该看到类似于以下的输出:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v3.4.6)
....... . . .
....... . . . (log output here)
....... . . .
........ Started MyApplication in 0.08 seconds (process running for 0.095)

注意:启动时间因机器而异,但它应该比在 JVM 上运行的 Spring Boot 应用快得多。

如果你在 Web 浏览器中打开 localhost:8080,你应该看到以下输出:

Hello World!

要优雅地退出应用,请按 ctrl-c