|
此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring GraphQL 1.3.3! |
请求执行
ExecutionGraphQlService是调用 GraphQL Java 执行的主要 Spring 抽象
请求。底层传输(如 HTTP)委托给ExecutionGraphQlService处理请求。
主要实现DefaultExecutionGraphQlService配置了GraphQlSource要访问graphql.GraphQL实例。
GraphQLSource
GraphQlSource是一个合约,用于公开graphql.GraphQLinstance 来使用该
包含用于构建该实例的构建器 API。默认构建器可通过GraphQlSource.schemaResourceBuilder().
Boot Starter 会创建此构建器的实例并进一步初始化它
要从可配置位置加载 Schema 文件,
公开要应用到的属性GraphQlSource.Builder,以检测RuntimeWiringConfigurerbeans、用于 GraphQL 指标的插桩 bean、
和DataFetcherExceptionResolver和SubscriptionExceptionResolverbean 来解决异常。对于进一步的自定义,您还可以
声明一个GraphQlSourceBuilderCustomizerbean,例如:
@Configuration(proxyBeanMethods = false)
class GraphQlConfig {
@Bean
public GraphQlSourceBuilderCustomizer sourceBuilderCustomizer() {
return (builder) ->
builder.configureGraphQl(graphQlBuilder ->
graphQlBuilder.executionIdProvider(new CustomExecutionIdProvider()));
}
}
Schema 资源
GraphQlSource.Builder可以配置一个或多个Resource实例为
解析并合并在一起。这意味着 schema 文件几乎可以从任何
位置。
默认情况下,Boot Starters会查找带有扩展名的 schema 文件
位置下的 “.graphqls” 或 “.gqls”classpath:graphql/**,这通常是src/main/resources/graphql.您还可以使用文件系统位置或任何位置
由 Spring 提供支持Resource层次结构,包括自定义实现
从远程位置、存储或内存加载架构文件。
用classpath*:graphql/**/在多个 Classpath 中查找 schema 文件
位置,例如跨多个模块。 |
Schema 创建
默认情况下,GraphQlSource.Builder使用 GraphQL JavaSchemaGenerator要创建graphql.schema.GraphQLSchema.这适用于典型用途,但如果您需要使用
不同的生成器,例如对于联合,您可以注册一个schemaFactory回调:
GraphQlSource.Builder builder = ...
builder.schemaResources(..)
.configureRuntimeWiring(..)
.schemaFactory((typeDefinitionRegistry, runtimeWiring) -> {
// create GraphQLSchema
})
GraphQlSource 部分解释了如何使用 Spring Boot 进行配置。
有关 Apollo Federation 的示例,请参见 federation-jvm-spring-example。
RuntimeWiringConfigurer
您可以使用RuntimeWiringConfigurer要注册:
-
自定义标量类型。
-
违约
TypeResolver用于接口和联合类型。 -
DataFetcher对于字段,尽管应用程序通常会使用带注释的控制器,并且 这些被检测并注册为DataFetchers byAnnotatedControllerConfigurer, 这是一个RuntimeWiringConfigurer.Boot Starter 会自动注册AnnotatedControllerConfigurer.
| GraphQL Java 服务器应用程序仅将 Jackson 用于与数据映射之间的序列化。 客户端输入被解析为 Map。服务器输出将根据字段选择集组装到地图中。 这意味着您不能依赖 Jackson 序列化/反序列化 Comments。 相反,您可以使用自定义标量类型。 |
Boot Starter 检测 bean 类型的RuntimeWiringConfigurer和
将它们注册到GraphQlSource.Builder.这意味着在大多数情况下,您将拥有
类似于 this 的配置:
@Configuration
public class GraphQlConfig {
@Bean
public RuntimeWiringConfigurer runtimeWiringConfigurer(BookRepository repository) {
GraphQLScalarType scalarType = ... ;
SchemaDirectiveWiring directiveWiring = ... ;
DataFetcher dataFetcher = QuerydslDataFetcher.builder(repository).single();
return wiringBuilder -> wiringBuilder
.scalar(scalarType)
.directiveWiring(directiveWiring)
.type("Query", builder -> builder.dataFetcher("book", dataFetcher));
}
}
如果您需要添加WiringFactory,例如,进行注册时要考虑到
schema definitions 中,实现替代configure方法,该方法同时接受RuntimeWiring.Builder和一个输出List<WiringFactory>.这允许您添加任何
然后按顺序调用的工厂数。
TypeResolver
GraphQlSource.Builder寄存 器ClassNameTypeResolver作为默认值TypeResolver用于尚未进行此类注册的 GraphQL 接口和联合
通过RuntimeWiringConfigurer.目的
一个TypeResolver在 GraphQL 中,Java 用于确定值的 GraphQL 对象类型
从DataFetcher对于 GraphQL Interface (图形QL 接口) 或 Union (联合) 字段。
ClassNameTypeResolver尝试将值的简单类名与 GraphQL 匹配
Object 类型,如果不成功,它还会导航其超类型,包括
基类和接口,寻找匹配项。ClassNameTypeResolver提供了一个
选项配置名称提取函数以及Class更改为 GraphQL 对象类型
名称映射应该有助于涵盖更多极端情况:
GraphQlSource.Builder builder = ...
ClassNameTypeResolver classNameTypeResolver = new ClassNameTypeResolver();
classNameTypeResolver.setClassNameExtractor((klass) -> {
// Implement Custom ClassName Extractor here
});
builder.defaultTypeResolver(classNameTypeResolver);
GraphQlSource 部分解释了如何使用 Spring Boot 进行配置。
指令
GraphQL 语言支持“描述替代运行时执行和 GraphQL 文档中的类型验证行为”。指令类似于 Java,但在 GraphQL 文档中的类型、字段、片段和作上声明。
GraphQL Java 提供了SchemaDirectiveWiringContract 帮助应用程序检测
和 handle 指令。有关更多详细信息,请参阅
GraphQL Java 文档。
在 Spring GraphQL 中,你可以注册一个SchemaDirectiveWiring通过RuntimeWiringConfigurer.Boot Starter 检测到
这样的 bean,所以你可能会有这样的东西:
@Configuration
public class GraphQlConfig {
@Bean
public RuntimeWiringConfigurer runtimeWiringConfigurer() {
return builder -> builder.directiveWiring(new MySchemaDirectiveWiring());
}
}
| 有关指令支持的示例,请查看 Graphql Java 库的扩展验证。 |
ExecutionStrategy
一ExecutionStrategy在 GraphQL 中,Java 驱动请求的字段的获取。
要创建ExecutionStrategy,您需要提供DataFetcherExceptionHandler.
默认情况下,Spring for GraphQL 会创建异常处理程序以使用,如 异常 中所述,并将其设置在GraphQL.Builder.然后,GraphQL Java 使用它来创建AsyncExecutionStrategy实例。
如果您需要创建自定义ExecutionStrategy中,您可以检测到DataFetcherExceptionResolvers 并以相同的方式创建异常处理程序,并使用
it 创建自定义ExecutionStrategy.例如,在 Spring Boot 应用程序中:
@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));
}
架构转换
您可以注册一个graphql.schema.GraphQLTypeVisitor通过builder.schemaResources(..).typeVisitorsToTransformSchema(..)如果要遍历
并在创建架构后对其进行转换,然后对架构进行更改。注意事项
这通常比 Schema Traversal 更昂贵
首选遍历而不是转换,除非您需要进行架构更改。
架构遍历
您可以注册一个graphql.schema.GraphQLTypeVisitor通过builder.schemaResources(..).typeVisitors(..)如果要在
它已创建,并且可能会将更改应用于GraphQLCodeRegistry.请记住,
但是,此类访客无法更改架构。如果需要更改架构,请参阅 架构转换。
Schema 映射检查
如果查询、更改或订阅作没有DataFetcher,则不会
返回任何数据,并且不会执行任何有用的作。同样,返回的架构类型的字段
通过一个作,该作既未通过DataFetcherregistration,也不是默认的PropertyDataFetcher,它会查找
匹配的 Java 对象属性,将始终为null.
GraphQL Java 不执行检查以确保覆盖每个架构字段,并且
可能会导致可能无法发现的差距,具体取决于测试覆盖率。在运行时
你可能会得到一个 “静音”null,或者如果字段不可为空,则为 error。作为较低级别
库,GraphQL Java 根本不了解DataFetcherimplementations 和
它们的返回类型,因此无法将架构类型结构与 Java 对象进行比较
结构。
Spring for GraphQL 定义了SelfDescribingDataFetcher接口以允许DataFetcher以公开返回类型信息。全部 SpringDataFetcher实现
实现此接口。这包括用于 Annotated Controllers 的那些,以及用于 Querydsl 和 Query by Example Spring Data 存储库的那些。对于带注释的
controllers 的 Controllers 中,返回类型派生自@SchemaMapping方法。
在启动时,Spring for GraphQL 可以检查架构字段、DataFetcher注册
以及从DataFetcher要检查的 implementations
如果所有 schema 字段都被显式注册的DataFetcher或
匹配的 Java 对象属性。检查还会执行反向检查,寻找DataFetcher针对不存在的架构字段的注册。
要启用架构映射检查,请执行以下作:
GraphQlSource.Builder builder = ...
builder.schemaResources(..)
.inspectSchemaMappings(report -> {
logger.debug(report);
})
下面是一个示例报告:
GraphQL schema inspection:
Unmapped fields: {Book=[title], Author[firstName, lastName]} (1)
Unmapped registrations: {Book.reviews=BookController#reviews[1 args]} (2)
Skipped types: [BookOrAuthor] (3)
| 1 | 未映射的架构字段及其源类型的列表 |
| 2 | 列表DataFetcher在不存在的字段上注册 |
| 3 | 跳过的架构类型列表,如下所述 |
架构字段检查可以执行的作是有限的,尤其是当存在
Java 类型信息不足。如果带注释的控制器方法是
声明返回java.lang.Object,或者如果返回类型具有未指定的泛型
参数,例如List<?>,或者如果DataFetcher不实现SelfDescribingDataFetcher返回类型甚至未知。在这种情况下,
Java 对象类型结构仍然未知,并且架构类型在
生成的报告。对于每个跳过的类型,都会记录一条 DEBUG 消息以说明原因
它被跳过了。
架构联合类型总是被跳过,因为控制器方法无法 在 Java 中声明这样的返回类型,Java 类型结构是未知的。
架构接口类型仅支持直接声明的字段,这些字段是
与由SelfDescribingDataFetcher.
不检查具体实现上的其他字段。这有待改进
在将来的版本中,还要检查 schemainterfaceimplementation types 和 try
在声明的 Java 返回类型的子类型之间查找匹配项。
Operation Caching
GraphQL Java 必须在执行作之前对其进行解析和验证。这可能会影响
性能显着。为避免需要重新分析和验证,应用程序可以
配置PreparsedDocumentProvider缓存和重用 Document 实例。GraphQL Java 文档提供了有关以下内容的更多详细信息
查询缓存PreparsedDocumentProvider.
在 Spring GraphQL 中,你可以注册一个PreparsedDocumentProvider通过GraphQlSource.Builder#configureGraphQl:
.
// 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))
GraphQlSource 部分解释了如何使用 Spring Boot 进行配置。
螺纹模型
大多数 GraphQL 请求都受益于获取嵌套字段的并发执行。这是
为什么当今大多数应用程序都依赖于 GraphQL Java 的AsyncExecutionStrategy,它允许
要返回的数据获取器CompletionStage以及并发执行而不是串行执行。
Java 21 和虚拟线程增加了一个重要的功能,可以有效地使用更多线程,但是 仍然需要并发执行,而不是串行执行,以便请求 执行以更快地完成。
Spring for GraphQL 支持:
-
响应式数据获取器,它们是 适应于
CompletionStage如预期AsyncExecutionStrategy. -
CompletionStage作为返回值。 -
Controller 方法,即 Kotlin 协程方法。
-
@SchemaMapping 和 @BatchMapping 方法可以返回
Callable提交到Executor例如 Spring FrameworkVirtualThreadTaskExecutor.要启用此功能,您必须配置Executor上AnnotatedControllerConfigurer.
Spring for GraphQL 在 Spring MVC 或 WebFlux 上运行作为传输。Spring MVC
使用异步请求执行,除非生成的CompletableFuture已完成
在 GraphQL Java 引擎返回后立即返回,如果
request 足够简单,不需要异步数据获取。
反应性的DataFetcher
默认的GraphQlSourcebuilder 启用对DataFetcher返回Mono或Flux这会将它们调整为CompletableFuture哪里Flux值被聚合
并转换为 List,除非请求是 GraphQL 订阅请求,
在这种情况下,返回值仍然是 Reactive StreamsPublisher用于流媒体
GraphQL 响应。
反应式DataFetcher可以依赖对从
传输层,例如从 WebFlux 请求处理,请参阅 WebFlux 上下文。
上下文传播
Spring for GraphQL 支持通过 GraphQL Java 透明地从 HTTP 传输传播上下文,并传递到DataFetcher以及它调用的其他组件。这包括ThreadLocal上下文
从 Spring MVC 请求处理线程和 ReactorContext来自 WebFlux
处理管道。
WebMvc 网络
一个DataFetcher和 GraphQL Java 调用的其他组件可能并不总是在
与 Spring MVC 处理程序相同的线程,例如,如果WebGraphQlInterceptor或DataFetcher切换到
不同的线程。
Spring for GraphQL 支持传播ThreadLocal来自 Servlet 容器的值
thread 设置为线程 aDataFetcher和其他组件,以
执行时间。为此,应用程序需要实现io.micrometer.context.ThreadLocalAccessor对于ThreadLocal感兴趣的值:
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();
}
}
您可以注册一个ThreadLocalAccessor在启动时使用全局ContextRegistry实例,可通过io.micrometer.context.ContextRegistry#getInstance().您也可以注册它
自动通过java.util.ServiceLoader机制。
WebFlux的
一个反应性的DataFetcher可以依赖对 Reactor 上下文的访问,该
源自 WebFlux 请求处理链。这包括 Reactor 上下文
由 WebGraphQlInterceptor 组件添加。
异常
在 GraphQL Java 中,DataFetcherExceptionHandler决定如何表示异常
在响应的 “errors” 部分中获取数据。应用程序可以注册
仅限单个处理程序。
Spring for GraphQL 注册了一个DataFetcherExceptionHandler提供默认
处理并启用DataFetcherExceptionResolver合同。应用程序可以
通过以下方式注册任意数量的解析器GraphQLSourcebuilder 中,这些位于
order 中,直到他们解决Exception更改为List<graphql.GraphQLError>.
Spring Boot Starters检测这种类型的 bean。
DataFetcherExceptionResolverAdapter是具有受保护方法的便捷基类resolveToSingleError和resolveToMultipleErrors.
带注释的控制器编程模型允许使用
具有灵活方法签名的带注释的异常处理程序方法,请参阅@GraphQlExceptionHandler了解详情。
一个GraphQLError可以根据 GraphQL Java 分配给类别graphql.ErrorClassification或 Spring GraphQLErrorType,其中定义了以下内容:
-
BAD_REQUEST -
UNAUTHORIZED -
FORBIDDEN -
NOT_FOUND -
INTERNAL_ERROR
如果异常仍未解决,则默认情况下,它被归类为INTERNAL_ERROR替换为包含类别名称和executionId从DataFetchingEnvironment.该消息故意不透明以避免泄漏
实现细节。应用程序可以使用DataFetcherExceptionResolver自定义
错误详细信息。
未解决的异常将记录在 ERROR 级别,并且executionId关联
发送到客户端的错误。已解决的异常记录在 DEBUG 级别。
请求例外
GraphQL Java 引擎在解析请求时可能会遇到验证或其他错误
这反过来又会阻止请求执行。在这种情况下,响应包含
“data” 键替换为null以及一个或多个请求级 “错误” 是全局的,即 not
具有字段路径。
DataFetcherExceptionResolver无法处理此类全局错误,因为它们是引发的
在执行开始之前和任何DataFetcher被调用。应用程序可以使用
传输级拦截器来检查和转换ExecutionResult.
请参阅下面的示例WebGraphQlInterceptor.
分页
GraphQL 游标连接规范定义了一种导航大型结果集的方法,方法是在以下时间返回项目子集 每个项目都与一个游标配对,客户端可以使用该游标在 或 在被引用项之后。
该规范将模式称为 “连接”。名称以
on Connection 是表示分页结果集的 Connection Type。都~Connection类型包含一个 “edges” 字段,其中~Edgetype 将实际项与游标配对,因为
以及带有布尔标志的 “pageInfo” 字段,用于指示是否有更多项目转发
和向后。
连接类型
Connection必须为每个需要分页的类型创建类型定义,添加
样板和干扰添加到架构中。Spring for GraphQL 提供ConnectionTypeDefinitionConfigurer在启动时添加这些类型(如果尚未添加)
存在于解析的架构文件中。这意味着在 schema 中,您只需要:
Query {
books(first:Int, after:String, last:Int, before:String): BookConnection
}
type Book {
id: ID!
title: String!
}
请注意 spec 定义的前向分页参数first和after客户端可以使用
请求给定游标之后的前 N 项,而last和before是落后的
pagination 参数来请求给定游标之前的最后 N 项。
接下来,配置ConnectionTypeDefinitionConfigurer如下:
GraphQlSource.schemaResourceBuilder()
.schemaResources(..)
.typeDefinitionConfigurer(new ConnectionTypeDefinitionConfigurer)
以下类型定义将透明地添加到 schema 中:
type BookConnection {
edges: [BookEdge]!
pageInfo: PageInfo!
}
type BookEdge {
node: Book!
cursor: String!
}
type PageInfo {
hasPreviousPage: Boolean!
hasNextPage: Boolean!
startCursor: String
endCursor: String
}
Boot Starter 寄存器ConnectionTypeDefinitionConfigurer默认情况下。
ConnectionAdapter
一旦 Connection Types 在 schema 中可用,您还需要
等效的 Java 类型。GraphQL Java 提供了这些 API,包括通用的Connection和Edge以及PageInfo.
一种选择是填充Connection并从控制器方法返回它,或者DataFetcher.但是,这需要样板代码来创建Connection,
创建游标,将每个项目包装为Edge,并创建PageInfo.
此外,您可能已经有一个底层的分页机制,例如在使用
Spring Data 存储库。
Spring for GraphQL 定义了ConnectionAdaptercontract 来调整 items 的容器
自Connection.适配器通过DataFetcherdecorator 的
通过ConnectionFieldTypeVisitor.您可以按如下方式对其进行配置:
ConnectionAdapter adapter = ... ;
GraphQLTypeVisitor visitor = ConnectionFieldTypeVisitor.create(List.of(adapter)) (1)
GraphQlSource.schemaResourceBuilder()
.schemaResources(..)
.typeDefinitionConfigurer(..)
.typeVisitors(List.of(visitor)) (2)
| 1 | 创建具有一个或多个ConnectionAdapters. |
| 2 | 抵制类型的访客。 |
有内置的 ConnectionAdapters 代表 Spring Data 的Window和Slice.您还可以创建自己的自定义适配器。ConnectionAdapter实现依赖于CursorStrategy自
为返回的项目创建游标。相同的策略也用于支持Subrangecontroller 方法参数,其中包含
pagination input 的 API 中。
CursorStrategy
CursorStrategy是一个合约,用于对引用
项在大型结果集中的位置。游标可以基于索引或
在键集上。
一个ConnectionAdapter使用它来对返回项目的游标进行编码。带注释的 Controllers 方法、Querydsl 存储库和 Query by Example 存储库使用它来解码分页请求中的游标,并创建一个Subrange.
CursorEncoder是一个相关的合约,它进一步编码和解码 String 游标为
使它们对客户不透明。EncodingCursorStrategy结合CursorStrategy替换为CursorEncoder.您可以使用Base64CursorEncoder,NoOpEncoder或创建自己的。
有一个内置的 CursorStrategy对于 Spring DataScrollPosition.Boot Starter 注册一个CursorStrategy<ScrollPosition>跟Base64Encoder当 Spring Data 存在时。
排序
在 GraphQL 请求中没有提供排序信息的标准方法。然而 分页取决于稳定的排序顺序。您可以使用默认订单,或者其他方式 公开输入类型并从 GraphQL 参数中提取排序详细信息。
内置了对 Spring Data 的Sort作为控制器
method 参数。要使其正常工作,您需要有一个SortStrategy豆。
批量加载
给定一个Book及其Author,我们可以创建一个DataFetcher一本书和另一本书
对于它的作者。这允许选择有作者或无作者的书籍,但这意味着书籍
和 authors 不会一起加载,这在查询多个
books 作为每本书的作者是单独加载的。这称为 N+1 选择
问题。
DataLoader
GraphQL Java 提供了一个DataLoader用于批量加载相关实体的机制。
您可以在 GraphQL Java 文档中找到完整的详细信息。下面是一个
工作原理摘要:
-
注册
DataLoader在DataLoaderRegistry,它可以加载给定唯一键的实体。 -
DataFetcher的 can accessDataLoader的 ID 值,并使用它们按 ID 加载实体。 -
一个
DataLoader通过返回 future 来延迟加载,以便可以批量完成。 -
DataLoader维护加载实体的每个请求缓存,该缓存可以进一步 提高效率。
BatchLoaderRegistry
GraphQL Java 中的完整批处理加载机制需要实现以下之一
几个BatchLoader接口,然后将它们包装并注册为DataLoaders
,名称位于DataLoaderRegistry.
Spring GraphQL 中的 API 略有不同。对于注册,只有一个
中央BatchLoaderRegistry公开工厂方法和构建器以创建和
注册任意数量的批量加载函数:
@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 声明了一个BatchLoaderRegistry你可以注入的 bean
您的配置,如上所示,或按顺序放入任何组件(如控制器)
注册批量加载函数。反过来,BatchLoaderRegistry被注入DefaultExecutionGraphQlService确保DataLoader每个请求的注册数。
默认情况下,DataLoadername 基于目标实体的类名。
这允许@SchemaMapping方法声明具有泛型类型的 DataLoader 参数,以及
无需指定名称。但是,可以通过BatchLoaderRegistrybuilder(如有必要)以及其他DataLoaderOptions.
配置默认DataLoaderOptions全局,以用作任何
registration,您可以覆盖 Boot 的BatchLoaderRegistrybean 并使用构造函数
为DefaultBatchLoaderRegistry接受Supplier<DataLoaderOptions>.
在许多情况下,在加载相关实体时,您可以使用 @BatchMapping 控制器方法,这是一种快捷方式
for 并替换需要使用BatchLoaderRegistry和DataLoader径直。
BatchLoaderRegistry还提供其他重要的好处。它支持访问
一样GraphQLContextfrom batch loading functions 和 from@BatchMapping方法
以及确保对它们的上下文传播。这就是预期应用的原因
以使用它。可以执行你自己的DataLoaderregistrations 直接注册,但
此类注册将放弃上述好处。
测试 Batch Loading
首先BatchLoaderRegistry在DataLoaderRegistry:
BatchLoaderRegistry batchLoaderRegistry = new DefaultBatchLoaderRegistry();
// perform registrations...
DataLoaderRegistry dataLoaderRegistry = DataLoaderRegistry.newRegistry().build();
batchLoaderRegistry.registerDataLoaders(dataLoaderRegistry, graphQLContext);
现在您可以访问和测试个人DataLoader如下所示:
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("...");
// ...