GraalVM 原生支持

Spring Framework 6.0 引入了将 Spring 应用程序编译为 GraalVM 原生镜像 的支持基础设施。如果您不熟悉 GraalVM,以及这与在 JVM 上部署的应用程序有何不同以及它对 Spring 应用程序意味着什么,请参阅专门的 Spring Boot 3.x 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` 方法签名中作为参数或返回类型公开。在构建的 提前(Ahead Of Time)处理阶段,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 通过此 `DataFetcher`,`BookRepository` 将公开一个 `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` 类型和所有作为字段公开的类型的相关提示