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. 对内部类型进行一些反射用于 schema 检查

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

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

原生服务器应用程序支持

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

如果您的应用程序“手动”注册 data fetcher,结果可能是一些类型不可被发现。此时您应该使用 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 存在于应用程序上下文中,并且它不会在方法签名中暴露 schema 中使用的 Java 类型。因此,无法使用上面部分描述的 AotProcessor 策略。对于客户端支持,Spring for GraphQL 嵌入了 客户端基础设施的相关可达性元数据。当涉及到应用程序使用的 Java 类型时,应用程序应采用与使用 @RegisterReflectionForBinding 的“手动”data fetcher 类似的策略

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 类型和作为字段暴露的所有类型注册相关的提示