ExecutionGraphQlService是调用 GraphQL Java 执行的主要 Spring 抽象 请求。底层传输(如 HTTP)委托给来处理请求。ExecutionGraphQlServicespring-doc.cn

主实现 配置了 用于访问要调用的实例。DefaultExecutionGraphQlServiceGraphQlSourcegraphql.GraphQLspring-doc.cn

GraphQLSource

GraphQlSource是一个 Contract 来公开要使用的实例 包含用于构建该实例的构建器 API。默认生成器可通过 获得。graphql.GraphQLGraphQlSource.schemaResourceBuilder()spring-doc.cn

Boot Starter 会创建此构建器的实例并进一步初始化它 要从可配置位置加载 Schema 文件, 公开要应用于的属性,检测 RuntimeWiringConfigurer bean,用于 GraphQL 指标插桩 bean, 和 bean 进行异常解决。对于进一步的自定义,您还可以 声明一个 bean,例如:GraphQlSource.BuilderDataFetcherExceptionResolverSubscriptionExceptionResolverGraphQlSourceBuilderCustomizerspring-doc.cn

@Configuration(proxyBeanMethods = false)
class GraphQlConfig {

	@Bean
	public GraphQlSourceBuilderCustomizer sourceBuilderCustomizer() {
		return (builder) ->
				builder.configureGraphQl(graphQlBuilder ->
						graphQlBuilder.executionIdProvider(new CustomExecutionIdProvider()));
	}
}

Schema 资源

GraphQlSource.Builder可以配置一个或多个实例 解析并合并在一起。这意味着 schema 文件几乎可以从任何 位置。Resourcespring-doc.cn

默认情况下,Boot Starters会查找带有扩展名的 schema 文件 位置下的“.graphqls”或“.gqls”,通常为 .您还可以使用文件系统位置或任何位置 受 Spring 层次结构支持,包括一个自定义实现 从远程位置、存储或内存加载架构文件。classpath:graphql/**src/main/resources/graphqlResourcespring-doc.cn

用于跨多个 Classpath 查找 schema 文件 位置,例如跨多个模块。classpath*:graphql/**/

Schema 创建

默认情况下,使用 GraphQL Java 创建 .这适用于典型用途,但如果您需要使用 不同的生成器,你可以注册一个回调:GraphQlSource.BuilderSchemaGeneratorgraphql.schema.GraphQLSchemaschemaFactoryspring-doc.cn

GraphQlSource.Builder builder = ...

builder.schemaResources(..)
		.configureRuntimeWiring(..)
		.schemaFactory((typeDefinitionRegistry, runtimeWiring) -> {
			// create GraphQLSchema
		})

有关如何使用 Spring Boot 进行配置的信息,请参见 GraphQlSource 部分。spring-doc.cn

如果对联合感兴趣,请参阅 Federation 部分。spring-doc.cn

RuntimeWiringConfigurer

A 可用于注册以下内容:RuntimeWiringConfigurerspring-doc.cn

Spring 应用程序通常不需要执行直接注册。 相反,控制器方法通过 注册为 s ,这是一个 .DataFetcherDataFetcherAnnotatedControllerConfigurerRuntimeWiringConfigurer
GraphQL Java 服务器应用程序仅将 Jackson 用于与数据映射之间的序列化。 客户端输入被解析为 Map。服务器输出将根据字段选择集组装到地图中。 这意味着您不能依赖 Jackson 序列化/反序列化 Comments。 相反,您可以使用自定义标量类型

Boot Starter 检测 type 为 在 .这意味着在大多数情况下,您将拥有 类似于 this 的配置:RuntimeWiringConfigurerGraphQlSource.Builderspring-doc.cn

@Configuration
public class GraphQlConfig {

	@Bean
	public RuntimeWiringConfigurer runtimeWiringConfigurer(BookRepository repository) {
		GraphQLScalarType scalarType = ... ;
		SchemaDirectiveWiring directiveWiring = ... ;
		return wiringBuilder -> wiringBuilder
				.scalar(scalarType)
				.directiveWiring(directiveWiring);
	}
}

如果您需要添加 ,例如,进行注册时要考虑 模式定义中,实现同时接受 和 output 的替代方法。这允许您添加任何 然后按顺序调用的工厂数。WiringFactoryconfigureRuntimeWiring.BuilderList<WiringFactory>spring-doc.cn

TypeResolver

GraphQlSource.Builderregisters 作为默认值,用于尚未进行此类注册的 GraphQL 接口和联合 通过 RuntimeWiringConfigurer。目的 a 用于确定值的 GraphQL 对象类型 从 for a GraphQL Interface 或 Union 字段返回。ClassNameTypeResolverTypeResolverTypeResolverDataFetcherspring-doc.cn

ClassNameTypeResolver尝试将值的简单类名与 GraphQL 匹配 Object 类型,如果不成功,它还会导航其超类型,包括 基类和接口,寻找匹配项。 提供了一个 选项来配置名称提取函数以及 GraphQL 对象类型 名称映射应该有助于涵盖更多极端情况:ClassNameTypeResolverClassspring-doc.cn

GraphQlSource.Builder builder = ...
ClassNameTypeResolver classNameTypeResolver = new ClassNameTypeResolver();
classNameTypeResolver.setClassNameExtractor((klass) -> {
	// Implement Custom ClassName Extractor here
});
builder.defaultTypeResolver(classNameTypeResolver);

有关如何使用 Spring Boot 进行配置的信息,请参见 GraphQlSource 部分。spring-doc.cn

指令

GraphQL 语言支持“描述替代运行时执行和 GraphQL 文档中的类型验证行为”。指令类似于 Java,但在 GraphQL 文档中的类型、字段、片段和操作上声明。spring-doc.cn

GraphQL Java 提供了帮助应用程序检测的协定 和 handle 指令。有关更多详细信息,请参阅 GraphQL Java 文档。SchemaDirectiveWiringspring-doc.cn

在 Spring GraphQL 中,你可以通过RuntimeWiringConfigurer注册一个。Boot Starter 检测到 这样的 bean,所以你可能会有这样的东西:SchemaDirectiveWiringspring-doc.cn

@Configuration
public class GraphQlConfig {

	 @Bean
	 public RuntimeWiringConfigurer runtimeWiringConfigurer() {
		  return builder -> builder.directiveWiring(new MySchemaDirectiveWiring());
	 }

}
有关指令支持的示例,请查看 Graphql Java 库的扩展验证

ExecutionStrategy

GraphQL Java 中的一个驱动请求的字段的获取。 要创建 ,您需要提供 . 默认情况下,Spring for GraphQL 会创建要使用的异常处理程序,如 异常 中所述,并将其设置在 .然后,GraphQL Java 使用它来创建具有配置的异常处理程序的实例。ExecutionStrategyExecutionStrategyDataFetcherExceptionHandlerGraphQL.BuilderAsyncExecutionStrategyspring-doc.cn

如果需要创建自定义 ,可以以相同的方式检测 s 并创建异常处理程序,并使用 it 创建自定义 .例如,在 Spring Boot 应用程序中:ExecutionStrategyDataFetcherExceptionResolverExecutionStrategyspring-doc.cn

@Bean
GraphQlSourceBuilderCustomizer sourceBuilderCustomizer(
		ObjectProvider<DataFetcherExceptionResolver> resolvers) {

	DataFetcherExceptionHandler exceptionHandler =
			DataFetcherExceptionResolver.createExceptionHandler(resolvers.stream().toList());

	AsyncExecutionStrategy strategy = new CustomAsyncExecutionStrategy(exceptionHandler);

	return sourceBuilder -> sourceBuilder.configureGraphQl(builder ->
			builder.queryExecutionStrategy(strategy).mutationExecutionStrategy(strategy));
}

架构转换

如果要遍历,可以注册一个 via 并在创建架构后对其进行转换,然后对架构进行更改。注意事项 这通常比 Schema Traversal 更昂贵 首选遍历而不是转换,除非您需要进行架构更改。graphql.schema.GraphQLTypeVisitorbuilder.schemaResources(..).typeVisitorsToTransformSchema(..)spring-doc.cn

架构遍历

如果要在 它已创建,并且可能会将更改应用于 .请记住, 但是,此类访客无法更改架构。如果需要更改架构,请参阅 架构转换graphql.schema.GraphQLTypeVisitorbuilder.schemaResources(..).typeVisitors(..)GraphQLCodeRegistryspring-doc.cn

Schema 映射检查

如果查询、更改或订阅操作没有 ,则不会 返回任何数据,并且不会执行任何有用的操作。同样,以下 schema 类型的字段 既未通过注册明确覆盖,也未由 default 查找匹配属性时,将始终为 .DataFetcherDataFetcherPropertyDataFetcherClassnullspring-doc.cn

GraphQL Java 不执行检查以确保覆盖每个架构字段,并且作为 较低级别的库,GraphQL Java 根本不知道 a 可以返回什么 或它所依赖的参数,因此无法执行此类验证。这可以 导致间隙,根据测试覆盖率,这些间隙可能直到运行时才被发现,当 客户端可能会遇到 “silent” 值或非 null 字段错误。DataFetchernullspring-doc.cn

Spring for GraphQL 中的接口允许 公开返回类型和预期参数等信息。控制器方法QuerydslQuery by Example 的所有内置 Spring 实现都是此接口的实现。对于带注解的控制器,返回类型和 预期参数基于控制器方法签名。这使得它可能 在启动时检查架构映射,以确保满足以下条件:SelfDescribingDataFetcherDataFetcherDataFetcherspring-doc.cn

  • 架构字段具有 registration 或相应的属性。DataFetcherClassspring-doc.cn

  • DataFetcherregistrations 引用存在的架构字段。spring-doc.cn

  • DataFetcher参数具有匹配的架构字段参数。spring-doc.cn

要启用 Schema 检查,请按如下所示进行自定义。 在这种情况下,报告只是记录下来,但您可以选择执行任何操作:GraphQlSource.Builderspring-doc.cn

GraphQlSource.Builder builder = ...

builder.schemaResources(..)
		.inspectSchemaMappings(report -> {
			logger.debug(report);
		});

示例报表:spring-doc.cn

GraphQL schema inspection:
    Unmapped fields: {Book=[title], Author[firstName, lastName]} (1)
    Unmapped registrations: {Book.reviews=BookController#reviews[1 args]} (2)
    Unmapped arguments: {BookController#bookSearch[1 args]=[myAuthor]} (3)
    Skipped types: [BookOrAuthor] (4)
1 未以任何方式覆盖的架构字段
2 DataFetcher对不存在的字段的注册
3 DataFetcher不存在的预期参数
4 已跳过的架构类型(接下来将解释)

在某些情况下,架构类型的类型是未知的。也许没有 implement ,或者声明的返回类型过于通用 (例如 ) 或未知 (例如 ),或者 可能完全缺失。 在这种情况下,架构类型将列为 skipped,因为无法验证。对于每个 skipped 类型,则会显示一条 DEBUG 消息,说明跳过它的原因。ClassDataFetcherSelfDescribingDataFetcherObjectList<?>DataFetcherspring-doc.cn

联合和接口

对于联合,检查会迭代成员类型并尝试查找相应的 类。对于接口,检查会迭代实现类型和 Look 对于相应的类。spring-doc.cn

默认情况下,在以下情况下,可以立即检测到相应的 Java 类:spring-doc.cn

  • 的简单名称与接口实现的 GraphQL 联合成员匹配 type name 的 JSON JSON 中,并且 与 controller 方法或控制器类,映射到 union 或 interface 字段。ClassClassspring-doc.cn

  • 在架构的其他部分进行检查,其中映射字段为 具体的 union 成员或接口实现类型。Classspring-doc.cn

  • 您已注册具有显式 GraphQL 类型映射的 TypeResolverClassspring-doc.cn

在上述帮助中没有,并且 GraphQL 类型在架构检查中报告为跳过 报告,您可以进行以下自定义:spring-doc.cn

  • 将 GraphQL 类型名称显式映射到一个或多个 Java 类。spring-doc.cn

  • 配置一个函数,用于自定义 GraphQL 类型名称如何适应简单名称。这有助于满足特定的 Java 类命名约定。Classspring-doc.cn

  • 提供 a 以映射 GraphQL 类型 a Java 类。ClassNameTypeResolverspring-doc.cn

例如:spring-doc.cn

GraphQlSource.Builder builder = ...

builder.schemaResources(..)
	.inspectSchemaMappings(
		initializer -> initializer.classMapping("Author", Author.class)
		logger::debug);

Operation Caching

GraphQL Java 必须在执行操作之前对其进行解析验证。这可能会影响 性能显着。为避免需要重新分析和验证,应用程序可以 配置 a 来缓存和重用 Document 实例。GraphQL Java 文档提供了有关以下内容的更多详细信息 查询缓存。PreparsedDocumentProviderPreparsedDocumentProviderspring-doc.cn

在 Spring GraphQL 中,您可以通过: .PreparsedDocumentProviderGraphQlSource.Builder#configureGraphQlspring-doc.cn

// Typically, accessed through Spring Boot's GraphQlSourceBuilderCustomizer
GraphQlSource.Builder builder = ...

// Create provider
PreparsedDocumentProvider provider =
        new ApolloPersistedQuerySupport(new InMemoryPersistedQueryCache(Collections.emptyMap()));

builder.schemaResources(..)
		.configureRuntimeWiring(..)
		.configureGraphQl(graphQLBuilder -> graphQLBuilder.preparsedDocumentProvider(provider))

有关如何使用 Spring Boot 进行配置的信息,请参见 GraphQlSource 部分。spring-doc.cn

用于跨多个 Classpath 查找 schema 文件 位置,例如跨多个模块。classpath*:graphql/**/
Spring 应用程序通常不需要执行直接注册。 相反,控制器方法通过 注册为 s ,这是一个 .DataFetcherDataFetcherAnnotatedControllerConfigurerRuntimeWiringConfigurer
GraphQL Java 服务器应用程序仅将 Jackson 用于与数据映射之间的序列化。 客户端输入被解析为 Map。服务器输出将根据字段选择集组装到地图中。 这意味着您不能依赖 Jackson 序列化/反序列化 Comments。 相反,您可以使用自定义标量类型
有关指令支持的示例,请查看 Graphql Java 库的扩展验证
1 未以任何方式覆盖的架构字段
2 DataFetcher对不存在的字段的注册
3 DataFetcher不存在的预期参数
4 已跳过的架构类型(接下来将解释)

螺纹模型

大多数 GraphQL 请求都受益于获取嵌套字段的并发执行。这是 为什么现在大多数应用程序都依赖于 GraphQL Java 的 ,它允许 数据获取器返回并发执行,而不是串行执行。AsyncExecutionStrategyCompletionStagespring-doc.cn

Java 21 和虚拟线程增加了一个重要的功能,可以有效地使用更多线程,但是 仍然需要并发执行,而不是串行执行,以便请求 执行以更快地完成。spring-doc.cn

Spring for GraphQL 支持:spring-doc.cn

Spring for GraphQL 在 Spring MVC 或 WebFlux 上运行作为传输。Spring MVC 使用异步请求执行,除非结果已完成 在 GraphQL Java 引擎返回后立即返回,如果 request 足够简单,不需要异步数据获取。CompletableFuturespring-doc.cn

反应性的DataFetcher

默认构建器支持返回 a 或将其调整为 where 值聚合 并转换为 List,除非请求是 GraphQL 订阅请求, 在这种情况下,返回值仍然是用于流式处理的 Reactive Streams GraphQL 响应。GraphQlSourceDataFetcherMonoFluxCompletableFutureFluxPublisherspring-doc.cn

响应式可以依赖从 传输层,例如从 WebFlux 请求处理,请参阅 WebFlux 上下文DataFetcherspring-doc.cn

上下文传播

Spring for GraphQL 支持通过 GraphQL Java 透明地从 HTTP 传输传播上下文,并传播到它调用的其他组件。这包括上下文 来自 Spring MVC 请求处理线程和 WebFlux 的 Reactor 处理管道。DataFetcherThreadLocalContextspring-doc.cn

WebMvc 网络

GraphQL Java 调用的 A 和其他组件可能并不总是在 与 Spring MVC 处理程序相同的线程,例如,如果异步 WebGraphQlInterceptor 或切换到 不同的线程。DataFetcherDataFetcherspring-doc.cn

Spring for GraphQL 支持从 Servlet 容器传播值 线程添加到线程 a 和其他组件中,GraphQL Java 调用到 执行时间。为此,应用程序需要实现感兴趣的值:ThreadLocalDataFetcherio.micrometer.context.ThreadLocalAccessorThreadLocalspring-doc.cn

public class RequestAttributesAccessor implements ThreadLocalAccessor<RequestAttributes> {

    @Override
    public Object key() {
        return RequestAttributesAccessor.class.getName();
    }

    @Override
    public RequestAttributes getValue() {
        return RequestContextHolder.getRequestAttributes();
    }

    @Override
    public void setValue(RequestAttributes attributes) {
        RequestContextHolder.setRequestAttributes(attributes);
    }

    @Override
    public void reset() {
        RequestContextHolder.resetRequestAttributes();
    }

}

您可以在启动时手动注册 全局实例,该实例可通过 访问。您也可以注册它 自动通过该机构。ThreadLocalAccessorContextRegistryio.micrometer.context.ContextRegistry#getInstance()java.util.ServiceLoaderspring-doc.cn

WebFlux的

响应式 DataFetcher 可以依赖于对 Reactor 上下文的访问,该上下文 源自 WebFlux 请求处理链。这包括 Reactor 上下文 由 WebGraphQlInterceptor 组件添加。spring-doc.cn

异常

在 GraphQL Java 中,决定如何表示 在响应的 “errors” 部分中获取数据。应用程序可以注册 仅限单个处理程序。DataFetcherExceptionHandlerspring-doc.cn

Spring for GraphQL 注册一个提供默认 处理并启用合约。应用程序可以 通过 GraphQLSource 构建器注册任意数量的解析程序,这些解析程序位于 order 直到一个他们解决 到 a . Spring Boot Starters检测这种类型的 bean。DataFetcherExceptionHandlerDataFetcherExceptionResolverExceptionList<graphql.GraphQLError>spring-doc.cn

DataFetcherExceptionResolverAdapter是一个方便的基类,其中包含受保护的方法 和 .resolveToSingleErrorresolveToMultipleErrorsspring-doc.cn

带注释的控制器编程模型允许使用 具有灵活方法签名的带注释的异常处理程序方法,有关详细信息,请参阅 @GraphQlExceptionHandlerspring-doc.cn

A 可以根据 GraphQL Java 或 Spring GraphQL 分配给类别,它定义了以下内容:GraphQLErrorgraphql.ErrorClassificationErrorTypespring-doc.cn

如果异常仍未解决,则默认情况下,该异常被归类为包含类别名称和 from 的通用消息。该消息故意不透明以避免泄漏 实现细节。应用程序可以使用 进行自定义 错误详细信息。INTERNAL_ERRORexecutionIdDataFetchingEnvironmentDataFetcherExceptionResolverspring-doc.cn

未解决的异常将记录在 ERROR 级别以及 to correlate 发送到客户端的错误。已解决的异常记录在 DEBUG 级别。executionIdspring-doc.cn

请求例外

GraphQL Java 引擎在解析请求时可能会遇到验证或其他错误 这反过来又会阻止请求执行。在这种情况下,响应包含 “data” 键,以及一个或多个请求级别的 “错误”,这些错误是全局的,即不是 具有字段路径。nullspring-doc.cn

DataFetcherExceptionResolver无法处理此类全局错误,因为它们是引发的 在执行开始之前和调用 any 之前。应用程序可以使用 传输级拦截器来检查和转换 . 请参阅 WebGraphQlInterceptor 下的示例。DataFetcherExecutionResultspring-doc.cn

包年包月例外

的 for a subscription 请求可能会完成并显示错误信号,在这种情况下 底层传输(例如 WebSocket)发送带有列表的最终 “error” 类型消息 的 GraphQL 错误。Publisherspring-doc.cn

DataFetcherExceptionResolver无法解决订阅 中的错误 由于数据仅创建初始。之后, transport 订阅 ,然后可能会完成并显示错误。PublisherDataFetcherPublisherPublisherspring-doc.cn

应用程序可以注册 a 以解析 exceptions 来解决这些问题为 GraphQL 错误 以发送到客户端。SubscriptionExceptionResolverPublisherspring-doc.cn

分页

GraphQL 游标连接规范定义了一种导航大型结果集的方法,方法是在以下时间返回项目子集 每个项目都与一个游标配对,客户端可以使用该游标在 或 在被引用项之后。spring-doc.cn

该规范将模式称为 “连接”。名称以 on Connection 是表示分页结果集的 Connection Type。所有类型都包含一个 “edges” 字段,其中 type 将实际项与游标配对,如 以及带有布尔标志的 “pageInfo” 字段,用于指示是否有更多项目转发 和向后。~Connection~Edgespring-doc.cn

连接类型

Connection必须为每个需要分页的类型创建类型定义,添加 样板和干扰添加到架构中。Spring for GraphQL 允许在启动时添加这些类型(如果尚未添加) 存在于解析的架构文件中。这意味着在 schema 中,您只需要:ConnectionTypeDefinitionConfigurerspring-doc.cn

Query {
	books(first:Int, after:String, last:Int, before:String): BookConnection
}

type Book {
	id: ID!
	title: String!
}

请注意 spec 定义的前向分页参数,并且客户端可以使用 请求给定游标之后的前 N 项,while 和 are backward pagination 参数来请求给定游标之前的最后 N 项。firstafterlastbeforespring-doc.cn

接下来,按如下方式进行配置:ConnectionTypeDefinitionConfigurerspring-doc.cn

GraphQlSource.schemaResourceBuilder()
		.schemaResources(..)
		.typeDefinitionConfigurer(new ConnectionTypeDefinitionConfigurer)

以下类型定义将透明地添加到 schema 中:spring-doc.cn

type BookConnection {
	edges: [BookEdge]!
	pageInfo: PageInfo!
}

type BookEdge {
	node: Book!
	cursor: String!
}

type PageInfo {
	hasPreviousPage: Boolean!
	hasNextPage: Boolean!
	startCursor: String
	endCursor: String
}

默认情况下,Boot Starter 会注册。ConnectionTypeDefinitionConfigurerspring-doc.cn

ConnectionAdapter

一旦 Connection Types 在 schema 中可用,您还需要 等效的 Java 类型。GraphQL Java 提供了这些选项,包括泛型 和 ,以及 .ConnectionEdgePageInfospring-doc.cn

一种选择是填充 a 并从控制器方法 或 .但是,这需要样板代码来创建 , 创建游标,将每个项目包装为 ,并创建 . 此外,您可能已经有一个底层的分页机制,例如在使用 Spring Data 存储库。ConnectionDataFetcherConnectionEdgePageInfospring-doc.cn

Spring for GraphQL 定义了适应项目容器的协定 自。适配器是通过一个装饰器应用的,而这个装饰器又是 通过 安装 .您可以按如下方式对其进行配置:ConnectionAdapterConnectionDataFetcherConnectionFieldTypeVisitorspring-doc.cn

ConnectionAdapter adapter = ... ;
GraphQLTypeVisitor visitor = ConnectionFieldTypeVisitor.create(List.of(adapter)) (1)

GraphQlSource.schemaResourceBuilder()
		.schemaResources(..)
		.typeDefinitionConfigurer(..)
		.typeVisitors(List.of(visitor)) (2)
1 创建具有一个或多个 s 的 type visitor 。ConnectionAdapter
2 抵制类型的访客。

Spring Data 和 有内置的 s。您还可以创建自己的自定义适配器。 实现依赖于 CursorStrategy 来 为返回的项目创建游标。相同的策略也用于支持 Subrange 控制器方法参数,该参数包含 pagination input 的 API 中。ConnectionAdapterWindowSliceConnectionAdapterspring-doc.cn

CursorStrategy

CursorStrategy是一个合约,用于对引用 项在大型结果集中的位置。游标可以基于索引或 在键集上。spring-doc.cn

ConnectionAdapter 使用它来对返回的 items 的游标进行编码。带注释的 Controllers 方法、Querydsl 存储库和 Query by Example 存储库使用它来解码分页请求中的游标,并创建一个 .Subrangespring-doc.cn

CursorEncoder是一个相关的合约,它进一步编码和解码 String 游标为 使它们对客户不透明。 与 .您可以使用 ,也可以创建自己的 。EncodingCursorStrategyCursorStrategyCursorEncoderBase64CursorEncoderNoOpEncoderspring-doc.cn

Spring Data 有一个内置的 。当 Spring Data 存在时,Boot Starter 会注册一个 with。CursorStrategyScrollPositionCursorStrategy<ScrollPosition>Base64Encoderspring-doc.cn

排序

在 GraphQL 请求中没有提供排序信息的标准方法。然而 分页取决于稳定的排序顺序。您可以使用默认订单,或者其他方式 公开输入类型并从 GraphQL 参数中提取排序详细信息。spring-doc.cn

内置了对 Spring Data 作为控制器的支持 method 参数。要使其正常工作,您需要有一个 bean。SortSortStrategyspring-doc.cn

1 创建具有一个或多个 s 的 type visitor 。ConnectionAdapter
2 抵制类型的访客。

批量加载

给定 a 及其 ,我们可以为一本书创建一个 和 另一个 对于它的作者。这允许选择有作者或无作者的书籍,但这意味着书籍 和 authors 不会一起加载,这在查询多个 books 作为每本书的作者是单独加载的。这称为 N+1 选择 问题。BookAuthorDataFetcherspring-doc.cn

DataLoader

GraphQL Java 提供了一种批量加载相关实体的机制。 您可以在 GraphQL Java 文档中找到完整的详细信息。下面是一个 工作原理摘要:DataLoaderspring-doc.cn

  1. Register 的 ,可以加载实体,给定唯一键。DataLoaderDataLoaderRegistryspring-doc.cn

  2. DataFetcher可以访问 并使用它们按 ID 加载实体。DataLoaderspring-doc.cn

  3. A 通过返回 future 来延迟加载,以便可以批量完成。DataLoaderspring-doc.cn

  4. DataLoader维护加载实体的每个请求缓存,该缓存可以进一步 提高效率。spring-doc.cn

BatchLoaderRegistry

GraphQL Java 中的完整批处理加载机制需要实现以下之一 several 接口,然后将它们包装并注册为 S 名称位于 .BatchLoaderDataLoaderDataLoaderRegistryspring-doc.cn

Spring GraphQL 中的 API 略有不同。对于注册,只有一个 Central 公开工厂方法和用于 create 和 注册任意数量的批量加载函数:BatchLoaderRegistryspring-doc.cn

@Configuration
public class MyConfig {

	public MyConfig(BatchLoaderRegistry registry) {

		registry.forTypePair(Long.class, Author.class).registerMappedBatchLoader((authorIds, env) -> {
				// return Mono<Map<Long, Author>
		});

		// more registrations ...
	}

}

Boot Starter 声明了一个可以注入的 bean 您的配置,如上所示,或按顺序放入任何组件(如控制器) 注册批量加载函数。反过来,它被注入到确保每个请求的注册的位置。BatchLoaderRegistryBatchLoaderRegistryDefaultExecutionGraphQlServiceDataLoaderspring-doc.cn

默认情况下,该名称基于目标实体的类名。 这允许方法使用泛型类型声明 DataLoader 参数,并且 无需指定名称。但是,如有必要,可以通过生成器自定义名称以及其他 .DataLoader@SchemaMappingBatchLoaderRegistryDataLoaderOptionsspring-doc.cn

要全局配置 default,要用作任何 registration,你可以覆盖 Boot 的 bean 并使用构造函数 因为接受 .DataLoaderOptionsBatchLoaderRegistryDefaultBatchLoaderRegistrySupplier<DataLoaderOptions>spring-doc.cn

在许多情况下,在加载相关实体时,您可以使用 @BatchMapping 控制器方法,这是一种快捷方式 for 和 replace 需要使用 和 直接。BatchLoaderRegistryDataLoaderspring-doc.cn

BatchLoaderRegistry还提供其他重要的好处。它支持访问 与 batch loading 函数和 from 方法相同, 以及确保对它们的上下文传播。这就是预期应用的原因 以使用它。可以直接执行自己的注册,但 此类注册将放弃上述好处。GraphQLContext@BatchMappingDataLoaderspring-doc.cn

测试 Batch Loading

首先在 上执行注册 :BatchLoaderRegistryDataLoaderRegistryspring-doc.cn

BatchLoaderRegistry batchLoaderRegistry = new DefaultBatchLoaderRegistry();
// perform registrations...

DataLoaderRegistry dataLoaderRegistry = DataLoaderRegistry.newRegistry().build();
batchLoaderRegistry.registerDataLoaders(dataLoaderRegistry, graphQLContext);

现在,您可以按如下方式访问和测试单个 :DataLoaderspring-doc.cn

DataLoader<Long, Book> loader = dataLoaderRegistry.getDataLoader(Book.class.getName());
loader.load(1L);
loader.loadMany(Arrays.asList(2L, 3L));
List<Book> books = loader.dispatchAndJoin(); // actual loading

assertThat(books).hasSize(3);
assertThat(books.get(0).getName()).isEqualTo("...");
// ...