Webflux/Reactor链式依赖API调用出现重复请求如何优化避免?
问题原因及解决方案
根本原因
你推测的触发逻辑完全正确。Reactor 中默认所有Mono/Flux均为冷发布者,每接收一次订阅请求,就会从头执行一次上游的完整处理链路。你的代码中users这个Mono对象被触发了两次订阅:
- 第一次是构造
parents对象时,依赖users的结果触发订阅 - 第二次是执行
Flux.merge(users, parents)时,对users的第二次订阅
两次订阅对应两次第二次API调用,因此总共产生4次API请求。
解决方案
方案1:添加缓存操作符复用结果
在users的定义末尾添加cache()操作符,第一次订阅得到的结果会被缓存,后续所有订阅直接复用缓存结果,不会重新触发上游的API调用。同时可优化原有冗余的map+flatMap写法,合并为单个flatMap:
Mono<List<Book>> books = bookService.find(params); //1st API call Mono<List<User>> users = books.flatMapMany(Flux::fromIterable) .map(User::getId) .collectList() .flatMap(userService::findUsers) //2nd API call,合并原有冗余写法 .cache(); // 新增:缓存调用结果,避免重复执行API Mono<List<User>> parents = users.flatMapMany(Flux::fromIterable) .filter(user -> user.getParentId() != null) .map(User::getParentId) .collectList() .flatMap(userService::findUsers); //3rd API call,同样优化冗余写法 Mono<List<User>> usersWithParents = Flux.merge(users, parents) .flatMapIterable(Function.identity()) .collectList();
该方案适合后续业务逻辑还需要单独复用users、parents对象的场景。
方案2:调整链式结构避免重复订阅
直接将后续处理逻辑放在flatMap内部,全程只对第二次API调用的结果订阅一次,无需额外缓存:
Mono<List<User>> usersWithParents = bookService.find(params) //1st API call .flatMapMany(Flux::fromIterable) .map(User::getId) .collectList() .flatMap(userService::findUsers) //2nd API call,仅执行1次 .flatMap(users -> { // 基于已拿到的users查询父账号,无需再次订阅上游 return Flux.fromIterable(users) .filter(user -> user.getParentId() != null) .map(User::getParentId) .collectList() .flatMap(userService::findUsers) //3rd API call .map(parents -> { // 合并两个结果集合 List<User> allUsers = new ArrayList<>(users); allUsers.addAll(parents); return allUsers; }); });
该方案没有额外缓存开销,链路逻辑更内聚,适合仅需要最终合并结果的场景。
内容的提问来源于stack exchange,提问作者KPACHblu
相关产品推荐
相关产品推荐

