Java WebFlux链接以调用多个服务和响应聚合

Java WebFlux链接以调用多个服务和响应聚合,java,spring-webflux,project-reactor,Java,Spring Webflux,Project Reactor,我最近开始使用WebFlux,需要关于如何链接多个服务和聚合响应的建议。这4个服务及其响应POJO类似于以下示例: class Response1{ String a1; String a2; } class Response2{ String b1; } class Response3{ String c1; } class Response4{ String d1; } 以及4项服务的签名: Flux<Response1> service1(

我最近开始使用WebFlux,需要关于如何链接多个服务和聚合响应的建议。这4个服务及其响应POJO类似于以下示例:

class Response1{
   String a1;
   String a2;
}

class Response2{
   String b1;
}

class Response3{
   String c1;
}

class Response4{
   String d1;
}
以及4项服务的签名:

Flux<Response1> service1(); 
Flux<Response2> service2(String a1); //output field of Response1(service 1)
Flux<Response3> service3(String b1); //output field of Response2(service 2)
Mono<Response4> service4(String a2); //output field of Response1(service 1)
所以首先我需要调用Service1,然后为每个响应调用service2,然后为每个响应调用service3(由service2返回)。另外,为service1返回的每个响应1调用service4(可以与service2和service3调用并行调用)。为了更新聚合的最终响应,我添加了两个额外的POJO以允许存储子响应,例如(相关位):

我看到所有服务都被调用,就像我看到日志一样。两个问题: 1.为什么看不到聚合的响应,会减少丢失它?
2.有更好的方法来实现这一点吗?

如果您不想等待
服务2
下一个
信号,您可以使用
合并方法4
。大概是这样的:

return service1().flatMap(response1 ->
        Flux.merge(service23Agg(response1.a1), service4Agg(response1.a2))
                .reduce((aggResponse, aggResponse2) -> new AggResponse(
                        response1.a1,
                        response1.a2,
                        Optional.ofNullable(aggResponse.d1)
                                .orElse(aggResponse2.d1),
                        Optional.ofNullable(aggResponse.response2s)
                                .orElse(aggResponse2.response2s))));
实用程序类和方法:

class AggContainer {
    final String b1;
    final List<Response3> response3s;

    AggContainer(String b1, List<Response3> response3s) {
        this.b1 = b1;
        this.response3s = response3s;
    }
}

class AggResponse {
    final String a1;
    final String a2;
    final String d1;
    final List<AggContainer> response2s;

    AggResponse(String a1, String a2, String d1, List<AggContainer> response2s) {
        this.a1 = a1;
        this.a2 = a2;
        this.d1 = d1;
        this.response2s = response2s;
    }

    AggResponse(String d1) {
        this.a1 = null;
        this.a2 = null;
        this.d1 = d1;
        this.response2s = null;
    }

    AggResponse(List<AggContainer> response2s) {
        this.a1 = null;
        this.a2 = null;
        this.d1 = null;
        this.response2s = response2s;
    }
}

private Mono<AggResponse> service23Agg(String a1) {
    return service2(a1).flatMap(response2 -> service3(response2.b1).collectList()
            .map(response3s -> new AggContainer(response2.b1, response3s)))
            .collectList()
            .map(AggResponse::new);
}

private Mono<AggResponse> service4Agg(String a2) {
    return service4(a2).map(response4 -> new AggResponse(response4.d1));
}
类聚集容器{
最终管柱b1;
最终名单答复3;
AggContainer(字符串b1,列表响应3S){
这1.b1=b1;
this.response3s=response3s;
}
}
阶级侵略{
最终串a1;
最终字符串a2;
最终字符串d1;
最终清单答复2;
攻击应答(字符串a1、字符串a2、字符串d1、列表应答2S){
这1.a1=a1;
这1.a2=a2;
这1.d1=d1;
this.response2s=response2s;
}
攻击性应答(字符串d1){
此值为0.a1=空;
此值为0.a2=空;
这1.d1=d1;
this.response2s=null;
}
攻击响应(列表响应2s){
此值为0.a1=空;
此值为0.a2=空;
此值为0.d1=空;
this.response2s=response2s;
}
}
专用单声道服务23AGG(字符串a1){
返回service2(a1).flatMap(response2->service3(response2.b1).collectList()
.map(response3s->newaggcontainer(response2.b1,response3s)))
.LIST()
.map(侵略:新的);
}
专用单声道服务4AGG(字符串a2){
返回服务4(a2).map(响应4->新攻击响应(响应4.d1));
}

在异步环境中,您应该非常小心处理可变集合。避免在反应性管道内更改它。

我让它正常工作,问题是POJO ACCASPONSE和ACCASPONSE2没有字段的get方法,因此JSON转换器没有显示值。添加get方法后,它的工作方式与预期的一样。我的第二个问题还有待回答,有没有更好的办法来处理这种情况?(一个问题是,这种方法有很多嵌套)请检查我的解决方案:谢谢,我喜欢你的两个建议(更好的方法,不要中途更改集合)。如果解决方案适合你的需要,你应该对其进行投票,并选择它作为正确答案。不过,我最终会等待更多评论。
public class AggResponse extends Response1{
    List<AggResponse2> response2s;// populated from service2 response
    String d1; // populated from service4 response

    public void add(AggResponse2 res2){
        if(response2s == null)
            response2s = new ArrayList<>();
        response2s.add(res2);
    }
}
public class AggResponse2 extends Response2{
    List<Response3> response3s;// populated from service3 response

    public void add(Response3 res3) {
        if (response3s == null)
            response3s = new ArrayList<>();
        response3s.add(res3);
    }
}
public Flux<AggResponse> aggregate() {
    return services.service1()
            .map(res1 -> new AggResponse(res1.getA1(), res1.getA2()))
            .flatMap(aggRes -> services.service2(aggRes.getA1())
                    .map(res2 -> {
                        AggResponse2 aggRes2 = new AggResponse2(res2.getB1());
                        aggRes.add(aggRes2);
                        return aggRes2;
                    })
                    .flatMap(aggRes2 -> services.service3(aggRes2.getB1())
                            .map(res3 -> {
                                aggRes2.add(res3);
                                return res3;
                            })
                            .reduce(aggRes2, (a, aggRes3) -> aggRes2)
                    )
                    .reduce(aggRes, (a, aggRes2) -> aggRes)
            )
            .flatMap(aggRes -> services.service4(aggRes.getA1())
                    .map(res4 -> {
                        aggRes.setD1(res4.getD1());
                        return aggRes;
                    })
            );
}
[ {
  "a1" : "a1v1",
  "a2" : "a2v1"
} ]
return service1().flatMap(response1 ->
        Flux.merge(service23Agg(response1.a1), service4Agg(response1.a2))
                .reduce((aggResponse, aggResponse2) -> new AggResponse(
                        response1.a1,
                        response1.a2,
                        Optional.ofNullable(aggResponse.d1)
                                .orElse(aggResponse2.d1),
                        Optional.ofNullable(aggResponse.response2s)
                                .orElse(aggResponse2.response2s))));
class AggContainer {
    final String b1;
    final List<Response3> response3s;

    AggContainer(String b1, List<Response3> response3s) {
        this.b1 = b1;
        this.response3s = response3s;
    }
}

class AggResponse {
    final String a1;
    final String a2;
    final String d1;
    final List<AggContainer> response2s;

    AggResponse(String a1, String a2, String d1, List<AggContainer> response2s) {
        this.a1 = a1;
        this.a2 = a2;
        this.d1 = d1;
        this.response2s = response2s;
    }

    AggResponse(String d1) {
        this.a1 = null;
        this.a2 = null;
        this.d1 = d1;
        this.response2s = null;
    }

    AggResponse(List<AggContainer> response2s) {
        this.a1 = null;
        this.a2 = null;
        this.d1 = null;
        this.response2s = response2s;
    }
}

private Mono<AggResponse> service23Agg(String a1) {
    return service2(a1).flatMap(response2 -> service3(response2.b1).collectList()
            .map(response3s -> new AggContainer(response2.b1, response3s)))
            .collectList()
            .map(AggResponse::new);
}

private Mono<AggResponse> service4Agg(String a2) {
    return service4(a2).map(response4 -> new AggResponse(response4.d1));
}