Spring Webflux中void与Mono<Void>的区别及业务场景优化问题
void与Mono的核心区别
- 普通
void是Java原生关键字,用于同步方法声明,代表方法执行完没有任何返回值,调用方法时逻辑会同步立即执行,执行完成就代表操作结束,出错会直接同步抛出异常。 Mono<Void>是Reactor框架中特殊的Publisher实现,专用于响应式异步场景,代表一个异步操作的状态信号:它不会发射任何数据元素,仅会在操作完成时发射「完成信号」,操作出错时发射「错误信号」。和同步void最大的差异是:Mono<Void>只有被订阅时才会触发内部逻辑执行,未订阅的话定义的操作永远不会运行,同时它可以无缝嵌入响应式流的链式调用中,衔接上下游的异步执行顺序。
现有校验逻辑的优化方案
原有代码里的boolean返回值完全是为了适配链式调用的冗余设计,语义上校验逻辑本身只有「校验通过继续执行」和「校验失败抛出异常」两种结果,不需要返回值,可通过以下两种方案优化:
方案1:保留同步校验,改用void返回
适合校验逻辑轻量、本身不需要异步执行的场景:
首先修改校验类,去掉冗余的boolean返回:
public class NameValidator { public static void validate(String name) { if(StringUtils.isEmpty(name)) { throw new RuntimeException("Invalid name"); } } }
修改业务服务的链式调用,用Mono.fromRunnable封装无返回值的同步校验逻辑,通过then衔接后续业务逻辑:
@Service public class ABCService { public Mono<String> getGreeting(String name) { return Mono.fromRunnable(() -> NameValidator.validate(name)) // 校验完成无报错后,执行后续返回问候语的逻辑 .then(Mono.just("Hello, "+name+". Welcome!")); } }
方案2:全响应式改造,返回Mono
适合校验逻辑可能包含异步操作(比如查库校验参数)的场景,完全贴合响应式编程规范:
首先改造校验类,直接返回校验状态对应的Mono信号:
public class NameValidator { public static Mono<Void> validate(String name) { if(StringUtils.isEmpty(name)) { // 校验失败返回错误信号 return Mono.error(new RuntimeException("Invalid name")); } // 校验通过返回空信号,代表操作完成无返回值 return Mono.empty(); } }
业务服务可以直接将校验方法嵌入链式调用:
@Service public class ABCService { public Mono<String> getGreeting(String name) { return NameValidator.validate(name) .then(Mono.just("Hello, "+name+". Welcome!")); } }
两种方案都去掉了无意义的boolean返回值,完全符合语义,同时保持了响应式链式调用的流畅性。
内容的提问来源于stack exchange,提问作者justAnotherDev
相关产品推荐
相关产品推荐

