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

如何仅在Reactor前置步骤无错误时执行后续操作?

问题:响应式校验无法阻止save方法执行

我希望通过一个需与数据库交互的响应式校验操作来保护save方法的调用,尝试了如下实现:

service.verifyThatStuffNotExists(stuff.number())
.then(
    service.save(stuff)
).map( 
    savedStuff -> ResponseEntity.created(...) 
);

其中校验方法verifyThatStuffNotExists在条件不满足时返回错误Mono,否则返回空Mono:

Mono<Void> verifyThatStuffNotExists(String stuffNumber) {
  return repository.exitsByNumber(stuffNumber)
      .flatMap(alreadyThere -> {
          if (alreadyThere) {
              return Mono.error(new StuffAlreadyExistingException("Some message"));
          } else {
              return Mono.empty();
          }
      });
}

但实际运行不符合预期:即使verify方法返回错误,save方法仍会被调用,似乎then操作符仅协调完成事件。请问还有什么解决办法?


原因分析

问题核心在于**then操作符的使用逻辑**和Java的立即求值特性:

  • 你直接将service.save(stuff)的执行结果传入then,这意味着save方法在构建响应式链的阶段就已经被调用,完全不受上游校验结果的控制。
  • then仅负责等待上游Mono的完成事件,但无法阻止提前创建的Mono对应的方法调用。

解决方案

方式1:用flatMap替代then

flatMap会在上游Mono正常完成后才执行后续逻辑,确保save仅在校验通过时触发:

service.verifyThatStuffNotExists(stuff.number())
    .flatMap(ignored -> service.save(stuff))
    .map(savedStuff -> ResponseEntity.created(...))

方式2:使用then的Supplier重载版本

通过传入Supplier延迟save方法的执行,只有上游校验正常完成时,才会调用Supplier获取save的Mono:

service.verifyThatStuffNotExists(stuff.number())
    .then(() -> service.save(stuff))
    .map(savedStuff -> ResponseEntity.created(...))

额外优化:简化校验方法

校验逻辑可以用filter+switchIfEmpty简化,可读性更强:

Mono<Void> verifyThatStuffNotExists(String stuffNumber) {
    return repository.existsByNumber(stuffNumber)
        .filter(exists -> !exists)
        .switchIfEmpty(Mono.error(new StuffAlreadyExistingException("Some message")))
        .then();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 07:52:42