Java 8 使用project reactor处理多个外部服务

Java 8 使用project reactor处理多个外部服务,java-8,reactive-programming,spring-webflux,project-reactor,Java 8,Reactive Programming,Spring Webflux,Project Reactor,我不熟悉反应式编程,并尝试使用ProjectReactor模拟下面的用例,但我发现将响应从一个服务调用传递到另一个依赖服务有点困难。如有任何建议或参考,将不胜感激 响应getDetails(请求输入请求){ 我尝试了下面的示例,它对一个服务调用有效,但无法将响应传递给其他相关服务调用 最新答复: Mono<Response> getDetails(Request inputRequest){ return Mono.just(inputRequest.getId()

我不熟悉反应式编程,并尝试使用ProjectReactor模拟下面的用例,但我发现将响应从一个服务调用传递到另一个依赖服务有点困难。如有任何建议或参考,将不胜感激

响应getDetails(请求输入请求){

我尝试了下面的示例,它对一个服务调用有效,但无法将响应传递给其他相关服务调用

最新答复:

Mono<Response> getDetails(Request inputRequest){
    
    return Mono.just(inputRequest.getId())
                    .flatMap(id->{
                        DbResponse res = getDBCall(id).block();
                        if(res == null){
                            return Mono.error(new DBException(....));
                        }
                        return Mono.zip(callExternalService1(res),callExternalService2(inputRequest));
                    }).flatMap(response->{
                        Response extser1 = response.getT1();
                        Response extser2 = response.getT2();
                        //any exceptions?
                        return Mono.zip(Mono.just(extser1),Mono.just(extser2),callExternalService3();
                    }).flatMap(response->callExternalService4(response.getT1(),response.getT2(),response.getT3())
                    });
}

private Mono<DbResponse> getDBCall(String id) {
        return Mono.fromCallable(()->dbservice.get(id))
                .subscribeOn(Schedulers.boundedElastic());
}
Mono-getDetails(请求输入请求){
返回Mono.just(inputRequest.getId())
.flatMap(id->{
DbResponse res=getDBCall(id).block();
如果(res==null){
返回Mono.error(newdbexception(..);
}
返回Mono.zip(callExternalService1(res),callExternalService2(inputRequest));
}).flatMap(响应->{
Response extser1=Response.getT1();
Response extser2=Response.getT2();
//有例外吗?
返回Mono.zip(Mono.just(extser1),Mono.just(extser2),调用externalservice3();
}).flatMap(response->callExternalService4(response.getT1()、response.getT2()、response.getT3())
});
}
专用Mono getDBCall(字符串id){
返回Mono.fromCallable(()->dbservice.get(id))
.subscribeOn(Schedulers.boundedElastic());
}
问题:

  • 如何在不使用块的情况下将Mono转换为DbResponse 手术
  • 如果任何外部服务失败,如何构建 flatmap内的故障响应并返回

  • 如果您的服务返回Mono响应(否则您必须转换它们),您可以使用zip进行并行调用:

        Mono.zip( callExternalService1( inputRequest ),
                  callExternalService2( inputRequest ) )
            .flatMap( resp1AndResp2 -> this.callExternalService3( resp1AndResp2.getT1(),
                                                                  resp1AndResp2.getT2() )
                                           .flatMap( response3 -> Mono.zip( callExternalService4( resp1AndResp2.getT1(),
                                                                                                  resp1AndResp2.getT2(),
                                                                                                  response3 ),
                                                                            callExternalService5( resp1AndResp2.getT1(),
                                                                                                  resp1AndResp2.getT2(),
                                                                                                  response3 ),
                                                                            callExternalService6( resp1AndResp2.getT1(),
                                                                                                  resp1AndResp2.getT2(),
                                                                                                  response3 ) )
                                                                      .flatMap( resp4AndResp5AndResp6 -> callLastExternalService( resp4AndResp5AndResp6.getT1(),
                                                                                                                                  resp4AndResp5AndResp6.getT2(),
                                                                                                                                  resp4AndResp5AndResp6.getT3() ) ) ) );
    

    如果您的服务返回Mono响应(否则您必须转换它们),您可以使用zip进行并行调用:

        Mono.zip( callExternalService1( inputRequest ),
                  callExternalService2( inputRequest ) )
            .flatMap( resp1AndResp2 -> this.callExternalService3( resp1AndResp2.getT1(),
                                                                  resp1AndResp2.getT2() )
                                           .flatMap( response3 -> Mono.zip( callExternalService4( resp1AndResp2.getT1(),
                                                                                                  resp1AndResp2.getT2(),
                                                                                                  response3 ),
                                                                            callExternalService5( resp1AndResp2.getT1(),
                                                                                                  resp1AndResp2.getT2(),
                                                                                                  response3 ),
                                                                            callExternalService6( resp1AndResp2.getT1(),
                                                                                                  resp1AndResp2.getT2(),
                                                                                                  response3 ) )
                                                                      .flatMap( resp4AndResp5AndResp6 -> callLastExternalService( resp4AndResp5AndResp6.getT1(),
                                                                                                                                  resp4AndResp5AndResp6.getT2(),
                                                                                                                                  resp4AndResp5AndResp6.getT3() ) ) ) );
    

    如果您有n个呼叫,并且您希望在steplock中移动(即,如果您有所有呼叫的响应,则向前移动),请使用
    zip
    。例如:

    Mono.zip(call1, call2)
        .flatMap(tuple2 -> {
             ResponseEntity<?> r1 = tuple2.getT1();    //response from call1
             ResponseEntity<?> r2 = tuple2.getT2();    //response from call2
             return Mono.zip(Mono.just(r1), Mono.just(r2), call3);
         })
        .flatMap(tuple3 -> {
             //at this point, you have r1, r2, r3. tuple3.getT1() response from call 1
             return Mono.zip(call4, call5, call6);   //tuple3.getT2() response from call 2, tuple3.getT3() response from call3
         })
        .flatMap(tuple3 -> callLastService);
    
    注意:
    Mono.callable(..)
    如果可调用返回空,则返回空流。这就是为什么
    switchIfEmpty

  • 您可以使用诸如
    onErrorResume
    之类的运算符提供回退流。请参阅:

  • 如果您有n个呼叫,并且您希望在steplock中移动(即,如果您有所有呼叫的响应,则向前移动),请使用
    zip
    。例如:

    Mono.zip(call1, call2)
        .flatMap(tuple2 -> {
             ResponseEntity<?> r1 = tuple2.getT1();    //response from call1
             ResponseEntity<?> r2 = tuple2.getT2();    //response from call2
             return Mono.zip(Mono.just(r1), Mono.just(r2), call3);
         })
        .flatMap(tuple3 -> {
             //at this point, you have r1, r2, r3. tuple3.getT1() response from call 1
             return Mono.zip(call4, call5, call6);   //tuple3.getT2() response from call 2, tuple3.getT3() response from call3
         })
        .flatMap(tuple3 -> callLastService);
    
    注意:
    Mono.callable(..)
    如果可调用返回空,则返回空流。这就是为什么
    switchIfEmpty

  • 您可以使用诸如
    onErrorResume
    之类的运算符提供回退流。请参阅:

  • 虽然这应该是可行的,但是不必要的嵌套通常是一种代码味道。我的回答背后的想法是解释如何使用reactor(按照要求)进行并行调用但是,如果他想有一个更干净的代码,他可以根据他的业务逻辑提取不同的块。在这种情况下,有必要有一个具体的例子…所以你的否决票是不合适的!我刚刚读了So关于否决票的指南,他们建议我们在答案确实错误时否决。这个答案不是-所以我想如果你能改变答案中的任何内容,我可以收回否决票(我的投票现在被锁定,除非你编辑你的答案)。但另一方面,您仍然可以在没有嵌套的情况下进行并行调用。虽然这应该可以工作,但也存在不必要的嵌套,这通常是一种代码味道。我的回答背后的想法是解释如何使用reactor(应要求)进行并行调用但是,如果他想有一个更干净的代码,他可以根据他的业务逻辑提取不同的块。在这种情况下,有必要有一个具体的例子…所以你的否决票是不合适的!我刚刚读了So关于否决票的指南,他们建议我们在答案确实错误时否决。这个答案不是-所以我想如果你能改变答案中的任何内容,我可以收回否决票(我的投票现在被锁定,除非你编辑你的答案)。但另一方面,您仍然可以在不嵌套的情况下进行并行调用。如果任何服务需要很长时间,主线程是否会退出?。我们是否使用块操作来等待所有外部服务得到处理?您不需要在此处进行块操作。正如我所说,zip在一个步锁中工作,因此当上述流发出时,它将是重锁最后一个服务的响应。I/O调用卸载到弹性线程后,主线程将立即退出。您不需要在此处阻止任何位置。您可以尝试运行代码一次,然后检查它是否对您有效。Prashant,是的,它正在工作+1。我已经发布了两个问题,您能帮助吗?@Prasanth,非常感谢。如果任何一个服务主线程会退出很长时间吗?我们不是使用阻塞操作来等待所有外部服务得到处理吗?这里不需要阻塞。正如我所说,zip在一个步锁中工作,因此当上述流发出时,它将是最后一个服务的响应。I/O调用卸载到弹性区域后,主线程就会退出d、 你不需要在这里阻止任何地方。你可以试着运行一次代码并检查它是否对你有效。Prashant,是的,它正在工作+1。我已经发布了两个问题,你能帮忙吗?@Prasanth,非常感谢。