从Spring Web控制器返回磁通量会怎样?

时间:2019-03-26 11:14:04

标签: spring-webflux project-reactor

我对反应式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返回了按顺序打印的数字(一个接一个)一样。
从控制器返回磁通量时到底发生了什么?

1 个答案:

答案 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响应进行响应。 Result delivered as single response

结果,您看不到反应式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端点的实际价值,该端点能够在日期可用时将结果传递给客户端。

Result get delivered as data get available

您可以在以下位置找到有关如何构建反应式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