使用 spring webclient with flux 避免多次调用 API
Avoid multiple calls to API using spring webclient with flux
这两个调用都是客户端 http api:
Flux<SavingsViewFilter> views = savingsApi.getViewFilterSavings(viewId);
Flux<Group> groups = groupsApi.getAllGroups();
和return一个通量
requestBodySpec.retrieve().bodyToFlux(returnType);
我需要根据来自 eacg view.getGroupId()
的值过滤 Flux<Group>
中的元素
return views.flatMap(view ->
groups
.filter(group -> Objects.equals(group.getGroupId(), view.getGroupId()))
.flatMap(group -> Flux.just(DepositAccount.builder()
.agencyName(group.getGroupName())
.settlementAccount(view.getName())
.build())));
它正在工作,但问题是它正在为每个视图对象执行一个到 getAllGroups 的 HTTP 请求。
如何避免对 getAllGroups 的多次请求?
问题是您正在为每个视图元素订阅组。
可以使用join只订阅each一次,然后逐个元素join。
views
//Join fluxes and create tuple for each pair
.join(groups, s-> Flux.never(),s-> Flux.never(),Tuples::of)
//Filter out any that don't have matching groupIds
.filter(t -> t.getT1().getGroupId().equals(t.getT2().getGroupId()))
//Use map, not flatMap since builder is not blocking
.map(t -> DepositAccount.builder()
.agencyName(t.getT2().getGroupName())
.settlementAccount(t.getT1().getName())
.build()
);
确实这不是正确的问题,需要更好地考虑一下。
最终结果是您试图将 views
的 ids
与 groups
的 ids
相匹配,并创建一个连接对象。这不是 Flux
API 的目的。最后看起来你正试图用两个循环来完成这个任务,这是一种非常低效的方法。
如果您研究替代方法会更好。
1) 如果group
和view
和数据库表都使用SQL加入。创建一个高效的新端点。
2) 将一个集合放入地图中,并使用它来组合两个实体。
@AllArgsConstructor
@Getter
class View {
Integer id;
String view;
}
@AllArgsConstructor
@Getter
class Group {
Integer id;
String group;
}
@Data
@AllArgsConstructor
class Combined {
String view;
String group;
}
private void run() {
Flux<View> views = Flux.just(new View(1, "v1"), new View(2, "v2"), new View(3, "v3"));
Flux<Group> groups = Flux.just(new Group(2, "g2"), new Group(3, "g3"), new Group(4, "g4"));
views.collectMap(View::getId)
.flatMapMany(viewMap -> groups.filter(group -> viewMap.containsKey(group.getId()))
.map(group ->
new Combined(viewMap.get(group.getId()).getView(), group.getGroup()))
)
.subscribe(System.out::println);
}
这两个调用都是客户端 http api:
Flux<SavingsViewFilter> views = savingsApi.getViewFilterSavings(viewId);
Flux<Group> groups = groupsApi.getAllGroups();
和return一个通量
requestBodySpec.retrieve().bodyToFlux(returnType);
我需要根据来自 eacg view.getGroupId()
Flux<Group>
中的元素
return views.flatMap(view ->
groups
.filter(group -> Objects.equals(group.getGroupId(), view.getGroupId()))
.flatMap(group -> Flux.just(DepositAccount.builder()
.agencyName(group.getGroupName())
.settlementAccount(view.getName())
.build())));
它正在工作,但问题是它正在为每个视图对象执行一个到 getAllGroups 的 HTTP 请求。
如何避免对 getAllGroups 的多次请求?
问题是您正在为每个视图元素订阅组。
可以使用join只订阅each一次,然后逐个元素join。
views
//Join fluxes and create tuple for each pair
.join(groups, s-> Flux.never(),s-> Flux.never(),Tuples::of)
//Filter out any that don't have matching groupIds
.filter(t -> t.getT1().getGroupId().equals(t.getT2().getGroupId()))
//Use map, not flatMap since builder is not blocking
.map(t -> DepositAccount.builder()
.agencyName(t.getT2().getGroupName())
.settlementAccount(t.getT1().getName())
.build()
);
确实这不是正确的问题,需要更好地考虑一下。
最终结果是您试图将 views
的 ids
与 groups
的 ids
相匹配,并创建一个连接对象。这不是 Flux
API 的目的。最后看起来你正试图用两个循环来完成这个任务,这是一种非常低效的方法。
如果您研究替代方法会更好。
1) 如果group
和view
和数据库表都使用SQL加入。创建一个高效的新端点。
2) 将一个集合放入地图中,并使用它来组合两个实体。
@AllArgsConstructor
@Getter
class View {
Integer id;
String view;
}
@AllArgsConstructor
@Getter
class Group {
Integer id;
String group;
}
@Data
@AllArgsConstructor
class Combined {
String view;
String group;
}
private void run() {
Flux<View> views = Flux.just(new View(1, "v1"), new View(2, "v2"), new View(3, "v3"));
Flux<Group> groups = Flux.just(new Group(2, "g2"), new Group(3, "g3"), new Group(4, "g4"));
views.collectMap(View::getId)
.flatMapMany(viewMap -> groups.filter(group -> viewMap.containsKey(group.getId()))
.map(group ->
new Combined(viewMap.get(group.getId()).getView(), group.getGroup()))
)
.subscribe(System.out::println);
}