You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Webflux中如何等待List<Mono>完成后执行后续异步调用?

解决Reactor中等待所有异步调用完成后再执行后续逻辑的问题

你的问题在Spring WebFlux(Reactor)的异步开发里很常见——你希望先让所有API2的并发调用执行完毕,再触发API3的请求,达到类似JavaScript中async/await配合Promise.all的效果。原代码的问题出在使用了subscribe():这个方法会直接触发异步执行,但不会让当前的Reactor流等待它完成,导致API3会在API2的结果还没处理完时就提前启动。

核心修正思路

  • 放弃用subscribe()触发API2调用,而是把每个API2请求封装成Mono<Covers>,收集为一个List<Mono<Covers>>
  • 利用Reactor的组合操作符(比如Mono.when())等待所有API2的Mono任务完成,统一获取结果
  • 等所有API2结果处理完毕后,再链式调用API3,最后组装并返回Artist对象

修正后的完整代码

import java.util.List;
import java.util.stream.Collectors;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public Mono<Artist> getArtistInfo(String id) {
    // 调用API1获取基础音乐数据
    Mono<MusicResponse> musicResponseMono = webClientBuilder
            .build()
            .get()
            .uri(uri + "\"" + id)
            .retrieve()
            .bodyToMono(MusicResponse.class);

    return musicResponseMono.flatMap(musicRes -> {
        Artist artist = new Artist();
        List<Albums> albums = musicRes.getAlbums();

        // 将每个专辑转换为API2的异步请求,收集为Mono列表
        List<Mono<Covers>> coverMonos = albums.stream()
                .map(album -> webClientBuilder
                        .build()
                        .get()
                        .uri("API 2 URL") // 这里记得替换为实际API2地址,可传入专辑相关参数如album.getId()
                        .retrieve()
                        .bodyToMono(Covers.class))
                .collect(Collectors.toList());

        // 等待所有API2请求完成,处理结果后再调用API3
        return Mono.when(coverMonos)
                // 取出所有API2的返回结果
                .thenMany(Flux.fromIterable(coverMonos))
                .flatMap(mono -> mono)
                // 将封面图片添加到Artist对象
                .doOnNext(cover -> artist.getAlbums().add(cover.getImage()))
                // 所有API2完成后,执行API3请求
                .then(webClientBuilder
                        .build()
                        .get()
                        .uri("API3 URL") // 替换为实际API3地址
                        .retrieve()
                        .bodyToMono(Profiles.class))
                // 处理API3结果,组装最终Artist并返回
                .map(profileRes -> {
                    artist.setDescription(profileRes.getDescription());
                    return artist;
                });
    });
}

关键细节解释

  1. 替换subscribe()为流内管理:
    原代码的subscribe()会脱离当前的Reactor流上下文,无法被后续操作等待。我们把每个API2请求封装成Mono并收集,让Reactor统一管理这些异步任务的生命周期。

  2. Mono.when()的作用:
    Mono.when(coverMonos)会等待所有传入的Mono任务完成,返回一个Mono<Void>信号,表示所有API2请求已结束。之后我们通过thenMany取出每个Mono的实际结果进行处理。

  3. 链式调用保证执行顺序:
    整个逻辑是严格的流式链式执行:API1完成 → 启动所有API2并等待全部完成 → 把API2结果写入Artist → 执行API3 → 返回最终组装好的Artist,完全避免了API3提前执行的问题。

额外优化建议

  • 不要每次请求都调用webClientBuilder.build(),建议在类中提前初始化并注入一个WebClient实例,减少重复创建对象的性能开销。
  • 如果API2的URL需要用到专辑的参数(比如专辑ID),记得在uri()中动态拼接,例如uri("api/albums/" + album.getId() + "/covers")。

内容的提问来源于stack exchange,提问作者Sourena Sahraian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:50:48