此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Boot 3.5.5spring-doc.cadn.net.cn

高级原生图像主题

嵌套配置属性

Spring 提前引擎会自动为配置属性创建反射提示。 但是,非内部类的嵌套配置属性必须使用@NestedConfigurationProperty,否则它们将不会被检测到并且无法绑定。spring-doc.cadn.net.cn

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;

@ConfigurationProperties("my.properties")
public class MyProperties {

	private String name;

	@NestedConfigurationProperty
	private final Nested nested = new Nested();

	// getters / setters...

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Nested getNested() {
		return this.nested;
	}

}

哪里Nested是:spring-doc.cadn.net.cn

public class Nested {

	private int number;

	// getters / setters...

	public int getNumber() {
		return this.number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

}
class Nested {

	var number: Int = 0
}

上面的示例生成了my.properties.namemy.properties.nested.number. 如果没有@NestedConfigurationProperty注释nested字段,my.properties.nested.number属性在本机映像中不可绑定。 您还可以注释 getter 方法。spring-doc.cadn.net.cn

使用构造函数绑定时,您必须使用@NestedConfigurationProperty:spring-doc.cadn.net.cn

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;

@ConfigurationProperties("my.properties")
public class MyPropertiesCtor {

	private final String name;

	@NestedConfigurationProperty
	private final Nested nested;

	public MyPropertiesCtor(String name, Nested nested) {
		this.name = name;
		this.nested = nested;
	}

	// getters / setters...

	public String getName() {
		return this.name;
	}

	public Nested getNested() {
		return this.nested;
	}

}
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;

@ConfigurationProperties("my.properties")
public record MyPropertiesRecord(String name, @NestedConfigurationProperty Nested nested) {

}

使用 Kotlin 时,您需要使用@NestedConfigurationProperty:spring-doc.cadn.net.cn

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.NestedConfigurationProperty

@ConfigurationProperties("my.properties")
data class MyPropertiesKotlin(
	val name: String,
	@NestedConfigurationProperty val nested: Nested
)
请在所有情况下使用公共 getter 和 setter,否则属性将不可绑定。

转换 Spring Boot 可执行 Jar

只要 jar 包含 AOT 生成的资产,就可以将 Spring Boot 可执行 jar 转换为本机映像。 这可能出于多种原因而有用,包括:spring-doc.cadn.net.cn

您可以使用 Cloud Native Buildpacks 或使用native-imageGraalVM 附带的工具。spring-doc.cadn.net.cn

可执行 jar 必须包含 AOT 生成的资产,例如生成的类和 JSON 提示文件。

使用构建包

Spring Boot 应用程序通常通过 Maven (mvn spring-boot:build-image) 或 Gradle (gradle bootBuildImage) 集成。 但是,您也可以使用pack将 AOT 处理的 Spring Boot 可执行 jar 转换为本机容器映像。spring-doc.cadn.net.cn

首先,确保 Docker 守护进程可用(有关更多详细信息,请参阅获取 Docker)。如果您使用的是 Linux,请将其配置为允许非 root 用户spring-doc.cadn.net.cn

您还需要安装pack按照 buildpacks.io 上的安装指南进行作。spring-doc.cadn.net.cn

假设 AOT 处理的 Spring Boot 可执行 jar 构建为myproject-0.0.1-SNAPSHOT.jartarget目录下,运行:spring-doc.cadn.net.cn

$ pack build --builder paketobuildpacks/builder-noble-java-tiny \
    --path target/myproject-0.0.1-SNAPSHOT.jar \
    --env 'BP_NATIVE_IMAGE=true' \
    my-application:0.0.1-SNAPSHOT
您无需安装本地 GraalVM 即可以这种方式生成映像。

一次pack已完成,您可以使用docker run:spring-doc.cadn.net.cn

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

使用 GraalVM native-image

将 AOT 处理的 Spring Boot 可执行文件 jar 转换为本机可执行文件的另一个选项是使用 GraalVMnative-image工具。 为此,您需要在计算机上安装 GraalVM 发行版。 您可以在 Liberica Native Image Kit 页面上手动下载它,也可以使用 SDKMAN!spring-doc.cadn.net.cn

假设 AOT 处理的 Spring Boot 可执行 jar 构建为myproject-0.0.1-SNAPSHOT.jartarget目录下,运行:spring-doc.cadn.net.cn

$ rm -rf target/native
$ mkdir -p target/native
$ cd target/native
$ jar -xvf ../myproject-0.0.1-SNAPSHOT.jar
$ native-image -H:Name=myproject @META-INF/native-image/argfile -cp .:BOOT-INF/classes:`find BOOT-INF/lib | tr '\n' ':'`
$ mv myproject ../
这些命令适用于 Linux 或 macOS 计算机,但您需要将它们调整为 Windows。
@META-INF/native-image/argfile可能没有打包在您的 jar 中。 仅当需要可访问性元数据覆盖时,才会包含它。
native-image -cp标志不接受通配符。 您需要确保列出所有 jar(上面的命令使用findtr来做到这一点)。

使用跟踪代理

GraalVM 本机映像跟踪代理允许您拦截 JVM 上的反射、资源或代理使用情况,以生成相关提示。 Spring 应该会自动生成其中的大部分提示,但跟踪代理可用于快速识别缺失的条目。spring-doc.cadn.net.cn

使用代理为本机图像生成提示时,有几种方法:spring-doc.cadn.net.cn

第一个选项对于识别 Spring 无法识别库或模式时缺少的提示很有趣。spring-doc.cadn.net.cn

第二个选项对于可重复的设置听起来更有吸引力,但默认情况下,生成的提示将包括测试基础设施所需的任何内容。 当应用程序实际运行时,其中一些将是不必要的。 为了解决这个问题,代理支持一个访问过滤器文件,该文件将导致某些数据从生成的输出中排除。spring-doc.cadn.net.cn

直接启动应用程序

使用以下命令启动附加了本机图像跟踪代理的应用程序:spring-doc.cadn.net.cn

$ java -Dspring.aot.enabled=true \
    -agentlib:native-image-agent=config-output-dir=/path/to/config-dir/ \
    -jar target/myproject-0.0.1-SNAPSHOT.jar

现在,您可以练习想要获得提示的代码路径,然后使用ctrl-c.spring-doc.cadn.net.cn

在应用程序关闭时,本机图像跟踪代理会将提示文件写入给定的配置输出目录。 您可以手动检查这些文件,也可以将它们用作本机映像生成过程的输入。 要将它们用作输入,请将它们复制到src/main/resources/META-INF/native-image/目录。 下次构建本机映像时,GraalVM 将考虑这些文件。spring-doc.cadn.net.cn

可以在本机图像跟踪代理上设置更高级的选项,例如按调用方类过滤记录的提示等。 如需进一步阅读,请参阅官方文档spring-doc.cadn.net.cn

自定义提示

如果您需要为反射、资源、序列化、代理使用等提供自己的提示,您可以使用RuntimeHintsRegistrar应用程序接口。 创建一个实现RuntimeHintsRegistrar接口,然后对提供的RuntimeHints实例:spring-doc.cadn.net.cn

import java.lang.reflect.Method;

import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.util.ReflectionUtils;

public class MyRuntimeHints implements RuntimeHintsRegistrar {

	@Override
	public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
		// Register method for reflection
		Method method = ReflectionUtils.findMethod(MyClass.class, "sayHello", String.class);
		hints.reflection().registerMethod(method, ExecutableMode.INVOKE);

		// Register resources
		hints.resources().registerPattern("my-resource.txt");

		// Register serialization
		hints.serialization().registerType(MySerializableClass.class);

		// Register proxy
		hints.proxies().registerJdkProxy(MyInterface.class);
	}

}

然后,您可以使用@ImportRuntimeHints在任何@Configuration类(例如,您的@SpringBootApplication带注释的应用程序类)来激活这些提示。spring-doc.cadn.net.cn

如果您有需要绑定的类(主要是在序列化或反序列化 JSON 时需要的),您可以使用@RegisterReflectionForBinding在任何豆子上。 大多数提示都是自动推断的,例如,当接受或返回来自@RestController方法。 但是,当您使用WebClient,RestClientRestTemplate直接,您可能需要使用@RegisterReflectionForBinding.spring-doc.cadn.net.cn

测试自定义提示

RuntimeHintsPredicatesAPI 可用于测试您的提示。 该 API 提供了构建Predicate可用于测试RuntimeHints实例。spring-doc.cadn.net.cn

如果您使用的是 AssertJ,您的测试将如下所示:spring-doc.cadn.net.cn

import org.junit.jupiter.api.Test;

import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.boot.docs.packaging.nativeimage.advanced.customhints.MyRuntimeHints;

import static org.assertj.core.api.Assertions.assertThat;

class MyRuntimeHintsTests {

	@Test
	void shouldRegisterHints() {
		RuntimeHints hints = new RuntimeHints();
		new MyRuntimeHints().registerHints(hints, getClass().getClassLoader());
		assertThat(RuntimeHintsPredicates.resource().forResource("my-resource.txt")).accepts(hints);
	}

}

静态提供提示

如果您愿意,可以在一个或多个 GraalVM JSON 提示文件中静态提供自定义提示。 此类文件应放在src/main/resources/META-INF/native-image/*/*/目录。 AOT 处理期间生成的提示将写入名为META-INF/native-image/{groupId}/{artifactId}/. 将静态提示文件放在与此位置不冲突的目录中,例如META-INF/native-image/{groupId}/{artifactId}-additional-hints/.spring-doc.cadn.net.cn

已知限制

GraalVM 本机映像是一项不断发展的技术,并非所有库都提供支持。 GraalVM 社区通过为尚未发布自己的项目提供可访问性元数据来提供帮助。 Spring 本身不包含第 3 方库的提示,而是依赖于可访问性元数据项目。spring-doc.cadn.net.cn

如果您在为 Spring Boot 应用程序生成原生镜像时遇到问题,请查看 Spring Boot wiki 的 Spring Boot with GraalVM 页面。 您还可以向 GitHub 上的 spring-aot-smoke-tests 项目贡献问题,该项目用于确认常见应用程序类型是否按预期工作。spring-doc.cadn.net.cn

如果您发现库不适用于 GraalVM,请在可访问性元数据项目上提出问题。spring-doc.cadn.net.cn