如何仅在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
相关产品推荐
相关产品推荐

