开发你的第一个 GraalVM 原生应用
构建 Spring Boot 原生镜像应用主要有两种方式:
-
使用 Spring Boot 对 Cloud Native Buildpacks 的支持 与 Paketo Java Native Image buildpack 生成一个包含原生可执行文件的轻量级容器。
-
使用 GraalVM Native Build Tools 生成原生可执行文件。
启动一个新的原生 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 images)正常工作。
使用 Buildpacks 构建 Native Image
Spring Boot 支持使用 Cloud Native Buildpacks(CNB)与 Maven 和 Gradle 集成,构建包含原生可执行文件的 Docker 镜像,并使用 Paketo Java Native Image buildpack。这意味着你只需输入一条命令,就能快速将一个合理的镜像推送到本地运行的 Docker daemon 中。生成的镜像不包含 JVM,而是将原生镜像静态编译而成。这使得镜像体积更小。
用于这些镜像的 CNB 构建器是 paketobuildpacks/builder-noble-java-tiny:latest。它具有较小的占用空间和更小的攻击面。该镜像不包含 shell,并且仅包含精简版的系统库。如果你需要在生成的镜像中包含更多工具,可以使用 paketobuildpacks/ubuntu-noble-run:latest 作为 run 镜像。
系统要求
应安装 Docker。更多详情请参见 Get Docker。如果你使用的是 Linux,请配置 Docker 以允许非 root 用户使用。
在 macOS 上,建议将分配给 Docker 的内存增加到至少 8GB,并可能同时增加 CPU 核心数。更多详情请参见这个 Stack Overflow 回答。在 Microsoft Windows 上,请确保启用 Docker WSL 2 后端 以获得更好的性能。
使用 Maven
要使用 Maven 构建原生镜像容器,你应该确保你的 pom.xml 文件使用了 spring-boot-starter-parent 和 org.graalvm.buildtools:native-maven-plugin。你应该有一个类似如下的 <parent> 部分:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.10</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 目标配置执行(executions)。
要构建镜像,你可以运行 spring-boot:build-image 目标,并激活 native 配置文件:
$ mvn -Pnative spring-boot:build-image
使用 Gradle
当应用 GraalVM Native Image 插件时,Spring Boot Gradle 插件会自动配置 AOT 任务。你应该检查你的 Gradle 构建文件中是否包含一个 plugins 块,并且其中包含 org.graalvm.buildtools.native。
只要应用了 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](http://localhost:8080),你应该会看到以下输出:
Hello World!
要优雅地退出应用程序,请按 ctrl-c。
使用 Native Build Tools 构建 Native Image
如果你想在不使用 Docker 的情况下直接生成原生可执行文件,可以使用 GraalVM Native Build Tools。Native Build Tools 是 GraalVM 为 Maven 和 Gradle 提供的插件。你可以使用它们来执行各种 GraalVM 任务,包括生成原生镜像(native image)。
先决条件
要使用 Native Build Tools 构建原生镜像,你需要在机器上安装一个 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 上,请按照 这些说明 安装 22.3 版本的 GraalVM 或 Liberica Native Image Kit、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 配置文件后,你可以调用 native:compile 目标来触发 native-image 编译:
$ mvn -Pnative native:compile
原生镜像可执行文件可以在 target 目录中找到。
使用 Gradle
当 Native Build Tools Gradle 插件被应用到你的项目时,Spring Boot Gradle 插件会自动触发 Spring AOT 引擎。任务依赖项会自动配置,因此你只需运行标准的 nativeCompile 任务即可生成原生镜像:
$ gradle nativeCompile
原生镜像可执行文件位于 build/native/nativeCompile 目录中。
运行示例
此时,你的应用程序应该可以正常运行了。你现在可以通过直接运行来启动该应用程序:
- Maven
- Gradle
$ target/myproject
$ build/native/nativeCompile/myproject
你应该看到类似如下的输出:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.5.10)
....... . . .
....... . . . (log output here)
....... . . .
........ Started MyApplication in 0.08 seconds (process running for 0.095)
启动时间因机器而异,但应该比在 JVM 上运行的 Spring Boot 应用快得多。
如果你在 Web 浏览器中打开 [localhost:8080](http://localhost:8080),你应该会看到以下输出:
Hello World!
要优雅地退出应用程序,请按 ctrl-c。