GraalVM 原生支持

Spring Framework 6.0 引入了支持基础设施,用于将 Spring 应用程序编译为 GraalVM 原生镜像。如果您不熟悉 GraalVM,以及它与在 JVM 上部署的应用程序有何不同,以及它对 Spring 应用程序意味着什么,请参阅专门的 Spring Boot 3.0 GraalVM 原生镜像支持文档。Spring Boot 还记录了 Spring 中 GraalVM 支持的已知限制

GraphQL Java 元数据

由于您的应用程序的静态分析是在构建时完成的,如果您的应用程序在运行时查找静态资源、执行反射或创建 JDK 代理,GraalVM 可能需要额外的提示。

GraphQL Java 在运行时执行了三个对原生镜像敏感的任务

  1. 加载资源包以进行消息国际化

  2. 对内部类型进行一些反射以进行模式检查

  3. 对应用程序在模式中注册的 Java 类型进行反射。例如,当 GraphQL Java 从应用程序类型中获取属性时,就会发生这种情况

前两项通过可达性元数据处理,该元数据由 Spring 团队贡献给GraalVM 可达性元数据存储库。构建依赖于 GraphQL Java 的应用程序时,原生编译工具会自动获取此元数据。这并不涵盖我们列表中的第三项,因为这些类型是由应用程序本身提供的,必须通过其他方式发现。

原生服务器应用程序支持

在典型的 Spring for GraphQL 应用程序中,与 GraphQL 模式绑定的 Java 类型在 @Controller 方法签名中作为参数或返回值类型公开。在构建的提前编译阶段,Spring 或 GraphQL 将使用其 o.s.g.data.method.annotation.support.SchemaMappingBeanFactoryInitializationAotProcessor 来发现相关类型并相应地注册可达性元数据。如果您正在构建一个支持 GraalVM 的 Spring Boot 应用程序,所有这些操作都会自动为您完成。

如果您的应用程序“手动”注册数据获取器,则某些类型无法发现。然后,您应该使用 Spring Framework 的 @RegisterReflectionForBinding 注册它们

import graphql.schema.DataFetcher;

import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.graphql.data.query.QuerydslDataFetcher;
import org.springframework.graphql.execution.RuntimeWiringConfigurer;

@Configuration
@RegisterReflectionForBinding(Book.class) (3)
public class GraphQlConfiguration {

	@Bean
	RuntimeWiringConfigurer customWiringConfigurer(BookRepository bookRepository) { (1)
		DataFetcher<Book> dataFetcher = QuerydslDataFetcher.builder(bookRepository).single();
		return (wiringBuilder) -> wiringBuilder
				.type("Query", (builder) -> builder.dataFetcher("book", dataFetcher)); (2)
	}

}
1 此应用程序声明一个 RuntimeWiringConfigurer,它“手动”添加一个 DataFetcher
2 通过此 DataFetcherBookRepository 将公开一个 Book 类型
3 @RegisterReflectionForBinding 将为 Book 类型及其所有作为字段公开的类型注册相关的提示

客户端支持

GraphQlClient 不一定作为应用程序上下文中的 bean 存在,并且它不会在方法签名中公开模式中使用的 Java 类型。因此,上面部分中描述的 AotProcessor 策略无法使用。对于客户端支持,Spring for GraphQL 嵌入客户端基础设施的相关可达性元数据。对于应用程序使用的 Java 类型,应用程序应该使用类似于使用 @RegisterReflectionForBinding 的“手动”数据获取器的策略

import reactor.core.publisher.Mono;

import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.graphql.client.GraphQlClient;
import org.springframework.stereotype.Component;

@Component
@RegisterReflectionForBinding(Project.class) (2)
public class ProjectService {

	private final GraphQlClient graphQlClient;

	public ProjectService(GraphQlClient graphQlClient) {
		this.graphQlClient = graphQlClient;
	}

	public Mono<Project> project(String projectSlug) {
		String document = """
				query projectWithReleases($projectSlug: ID!) {
					project(slug: $projectSlug) {
						name
						releases {
							version
						}
					}
				}
				""";

		return this.graphQlClient.document(document)
				.variable("projectSlug", projectSlug)
				.retrieve("project")
				.toEntity(Project.class); (1)
	}
}
1 在原生镜像中,我们需要确保在运行时可以对Project进行反射。
2 @RegisterReflectionForBinding将为Project类型及其所有作为字段公开的类型注册相关的提示。