Java WebFlux链接以调用多个服务和响应聚合
我最近开始使用WebFlux,需要关于如何链接多个服务和聚合响应的建议。这4个服务及其响应POJO类似于以下示例: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(
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));
}