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

基于Reactor Mono/Flux实现遍历PrincipalProvider列表并返回首个有效用户的异步改造方案咨询

嗨,这个场景用Reactor的操作符就能完美复刻原同步逻辑的行为,而且非常优雅!

首先咱们先更新接口,把返回值改成Mono<User>:

public interface PrincipalProvider {
    Mono<User> findUser(String name);
}

接下来是PrincipalProviderComposite的异步实现,核心思路是按顺序逐个调用每个Provider的findUser,一旦找到第一个有效(非空)的用户就停止后续调用,完全对应原同步代码的遍历+break逻辑:

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Objects;

public class PrincipalProviderComposite implements PrincipalProvider {
    private final List<PrincipalProvider> providers;

    public PrincipalProviderComposite(List<PrincipalProvider> providers) {
        this.providers = providers;
    }

    @Override
    public Mono<User> findUser(String name) {
        return Flux.fromIterable(providers)
                // 用concatMap保证顺序调用,和原同步逻辑的遍历顺序一致,不会并行触发多个Provider
                .concatMap(provider -> provider.findUser(name))
                // 过滤掉null结果,对应原代码里的if(user != null)判断
                .filter(Objects::nonNull)
                // 取第一个符合条件的结果,一旦找到就会取消后续所有Provider的调用(对应break)
                .next()
                // 可选:如果所有Provider都没找到,返回null而不是Mono.empty(),完全对齐原同步代码的返回语义
                .defaultIfEmpty(null);
    }
}

关键细节说明:

  • concatMap的作用:它会按顺序处理每个Provider的Mono<User>,只有当前一个Mono完成后才会触发下一个,这和原同步代码的遍历逻辑完全一致,避免了并行调用带来的不必要开销。
  • filter(Objects::nonNull):如果你的Provider约定没找到用户时返回Mono.empty()而非Mono.just(null),那这个filter可以去掉,因为concatMap会自动忽略空Mono的元素。
  • next():这个操作符会订阅Flux,一旦收到第一个有效元素就会发出onNext信号,同时取消后续所有订阅,完美对应原代码里的break逻辑,不会再调用后面的Provider。
  • defaultIfEmpty(null):原同步代码在所有Provider都没找到时返回null,这个操作符可以让异步版本的返回语义和原代码完全一致,如果你的调用方更倾向于处理Mono.empty(),可以去掉这一行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 02:57:36