如何在Java中使用Mono实现响应式条件循环?
响应式管道中实现条件循环的正确方式
你的需求是在响应式管道里实现类似非响应式do-while的逻辑:先执行一次操作,然后判断条件,只要roundNumber < 超时时间且proof == null就继续循环,直到条件不满足时返回最终的proof,再执行后续处理。
原代码的问题
你尝试的代码存在两个核心问题:
doOnSuccess是副作用操作,它不会修改流中传递的数据。你在其中创建的Pair并没有被传递到后续的repeat操作符中,repeat拿到的其实是handleProofRequest返回的proof对象,导致条件判断完全失效。- 嵌套的
flatMap结构错误,没有将roundNumber的判断结果和proof一起传递到下游,无法为循环提供正确的终止条件。
正确实现方式
方式一:递归调用(直观符合do-while逻辑)
将循环逻辑封装为递归方法,每次执行完单次尝试后判断是否需要继续循环:
// 封装单次尝试逻辑,返回当前的proof或继续递归 private Mono<String> attemptProofUntilCondition(Record record, Order order) { return handleDelayedRoundNumber() .flatMap(roundNumber -> handleProofRequest(record, order) .flatMap(proof -> { // 判断是否需要继续循环:round未超时且proof为空 boolean shouldContinue = roundNumber < order.clientMetadata().timeout() && proof == null; if (shouldContinue) { // 继续递归执行下一次尝试 return attemptProofUntilCondition(record, order); } else { // 终止循环,返回当前proof return Mono.just(proof); } })); } // 调用逻辑 attemptProofUntilCondition(record, order) .flatMap(this::doStuffWithProof);
方式二:使用repeatWhenEmpty(响应式风格)
利用repeatWhenEmpty操作符,只有当需要继续循环时才重新订阅上游:
// 单次尝试,返回包含是否继续循环的标识和proof的Pair private Mono<Pair<Boolean, String>> singleProofAttempt(Record record, Order order) { return handleDelayedRoundNumber() .flatMap(roundNumber -> handleProofRequest(record, order) .map(proof -> { boolean shouldRepeat = roundNumber < order.clientMetadata().timeout() && proof == null; return new Pair<>(shouldRepeat, proof); })); } // 调用逻辑 singleProofAttempt(record, order) // 只有当shouldRepeat为true时,才重复订阅上游 .repeatWhenEmpty(flux -> flux.flatMap(pair -> pair.first() ? Mono.just(true) : Mono.empty())) // 取最后一次尝试的结果 .last() // 提取proof .map(Pair::getSecond) .flatMap(this::doStuffWithProof);
非响应式逻辑对应说明
上述代码完全对应你给出的非响应式do-while逻辑:
Order order = ...; Record record = ...; String proof; do { int roundNumber = handleDelayedRoundNumber(); proof = handleProofRequest(record, order); } while(roundNumber < order.clientMetadata().timeout() && proof == null); doStuffWithProof(proof);
内容的提问来源于stack exchange,提问作者Marko Taht
相关产品推荐
相关产品推荐

