如何提供 Mono Consumers 作为方法参数?

时间:2021-04-14 12:03:45

标签: java spring spring-webflux project-reactor

我有一个通用方法,可以并行执行一堆请求,将它们发送到外部 Web api,并收集结果。

问题:调用者应该能够为 Web 请求的子例程提供成功和错误处理程序。但是如何?

示例:

public <Req, Rsp> List<Rsp> sendApiRequests(List<Req> requests, Class<Rsp> type) {
    return Flux.fromIterable(requests)
            .flatMap(req -> webClient.post()
                       .uri(uri)
                       .bodyValue(req)
                       .retrieve()
                       .bodyToMono(type)
                       .//TODO how can I add a generic handler methods here?
                       .)
            .filter(rsp -> rsp.success() && rsp.results > 0) //some common filters
            .collectList()
            .block();
}

调用者应该能够提供一个非常可能的子程序。例如,它可以提供.doOnSuccess().doOnerror().onErrorMap() 函数。还有任何其他或全部。

伪代码:

sendApiRequests(req, MyDto.class, req -> <subroutine>.doOnSuccess(..)
                                                     .doOnError(..)
                                                     .onErrorResume(..));

这可能吗?因为我没有将 Mono 请求中的 webClient.post() 暴露给调用者,所以我不知道如何在其上链接处理程序方法。

2 个答案:

答案 0 :(得分:1)

您可以在此处使用变换运算符。我不会称之为添加“消费者”,而是在反应管道中的特定点插入额外的运算符。它看起来像:

public String blockingCall(Function<Mono<String>, Publisher<String>> transformer) {
    return Mono.just("hi")
               .transform(transformer)
               .block();
}

并像这样使用它:

blockingCall(it -> it.doOnSuccess(...).doOnError(...))

答案 1 :(得分:1)

您应该使用 Mono#transform。来自 Reactor 的 documentation

<块引用>

transform 运算符让您可以将一段运算符链封装到一个函数中。该函数在汇编时应用于原始运算符链,以使用封装的运算符对其进行扩充。这样做对序列的所有订阅者应用相同的操作,基本上等同于直接链接操作符。

就你而言:

public <Req, Rsp> List<Rsp> sendApiRequests(List<Req> requests, Class<Rsp> type, Function<Mono<Rsp>, Mono<Rsp>> subroutine) {
        return Flux.fromIterable(requests)
                .flatMap((Req req) -> webClient.post()
                        .uri(uri)
                        .bodyValue(req)
                        .retrieve()
                        .bodyToMono(type)
                        .transform(subroutine)
                )
                .filter(rsp -> rsp.success() && rsp.results > 0) //some common filters
                .collectList()
                .block();
    }