我对反应式API比较陌生,并且对我们从Web控制器返回Flux时发生的幕后情况感到好奇。
根据spring-web文档
反应性返回值的处理方式如下:
与使用DeferredResult相似,单值承诺也适用。示例包括Mono(Reactor)或Single(RxJava)。
类似于使用ResponseBodyEmitter或SseEmitter,具有流媒体类型(例如application / stream + json或text / event-stream)的多值流适用于。示例包括Flux(反应堆)或Observable(RxJava)。应用程序还可以返回Flux或Observable。
具有任何其他媒体类型(例如application / json)的多值流都经过修改,类似于使用
DeferredResult<List<?>>
。
我创建了两个API,如下所示:
@GetMapping("/async-deferredresult")
public DeferredResult<List<String>> handleReqDefResult(Model model) {
LOGGER.info("Received async-deferredresult request");
DeferredResult<List<String>> output = new DeferredResult<>();
ForkJoinPool.commonPool().submit(() -> {
LOGGER.info("Processing in separate thread");
List<String> list = new ArrayList<>();
for (int i = 0; i < 10000 ; i++) {
list.add(String.valueOf(i));
}
output.setResult(list);
});
LOGGER.info("servlet thread freed");
return output;
}
@GetMapping(value = "/async-flux",produces = MediaType.APPLICATION_JSON_VALUE)
public Flux<String> handleReqDefResult1(Model model) {
LOGGER.info("Received async-deferredresult request");
List<String> list = new ArrayList<>();
list.stream();
for (int i = 0; i < 10000 ; i++) {
list.add(String.valueOf(i));
}
return Flux.fromIterable(list);
}
因此,例外情况是两个API的行为应与多值流(Flux)的行为与返回DeferredResult的行为类似。
但是在返回延迟结果的API中,整个列表是在浏览器中一次打印的,就像在API中,Flux返回了按顺序打印的数字(一个接一个)一样。
从控制器返回磁通量时到底发生了什么?
答案 0 :(得分:0)
当我们从服务端点返回Flux时,可能会发生许多事情。但是我假设您想知道当Flux作为来自此终结点客户端的事件流观察到时发生了什么。
场景一:通过添加“ application / json”作为端点的内容类型,Spring将与客户端进行通信以期望JSON主体。
@GetMapping(value = "/async-flux", produces = MediaType.APPLICATION_JSON_VALUE)
public Flux<String> handleReqDefResult1(Model model) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
list.add(String.valueOf(i));
}
return Flux.fromIterable(list);
}
客户端的输出将一次性显示整个数字集。并且一旦响应传递完毕,连接将被关闭。即使您将Flux用作响应类型,也仍然受制于HTTP over TCP / IP的工作原理。端点收到一个HTTP请求,执行逻辑并以包含最终结果的HTTP响应进行响应。
结果,您看不到反应式api的真实值。
场景二:通过添加“ application / stream + json”作为端点的内容类型,Spring开始将Flux流的结果事件视为单独的JSON项。发出项目后,将对其进行序列化,刷新HTTP响应缓冲区,并保持从服务器到客户端的连接打开,直到事件序列完成。
要使该代码正常工作,我们可以按如下所示稍微修改您的原始代码。
@GetMapping(value = "/async-flux",produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<String> handleReqDefResult1(Model model) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 10000 ; i++) {
list.add(String.valueOf(i));
}
return Flux.fromIterable(list)
// we have 1 sec delay to demonstrate the difference of behaviour.
.delayElements(Duration.ofSeconds(1));
}
这次,我们可以看到反应式api端点的实际价值,该端点能够在日期可用时将结果传递给客户端。
您可以在以下位置找到有关如何构建反应式REST api的更多详细信息 https://medium.com/@senanayake.kalpa/building-reactive-rest-apis-in-java-part-1-cd2c34af55c6 https://medium.com/@senanayake.kalpa/building-reactive-rest-apis-in-java-part-2-bd270d4cdf3f