本文详解在 Reactor 的 Mono 链中如何安全、可控地显式抛出异常,避免 doOnNext 误用导致错误无法传播,并通过 flatMap + Mono.error() 实现验证失败时触发重试机制。
本文详解在 reactor 的 mono 链中如何安全、可控地显式抛出异常,避免 `doonnext` 误用导致错误无法传播,并通过 `flatmap` + `mono.error()` 实现验证失败时触发重试机制。
在响应式编程中,Mono 的链式操作强调不可变性与声明式错误传播。常见的误区是试图在副作用操作符(如 doOnNext)中抛出异常——这会导致异常被静默吞没或触发 OnErrorNotImplementedException,而非进入正常的错误处理流程(如 onErrorResume 或重试策略)。
正确做法是:将业务验证逻辑纳入流的转换过程,使用 flatMap 将 Response 映射为新的 Mono
以下是推荐实现方式:
public Mono<response> handleResponse() {
return userService.getUser()
.flatMap(response -> {
try {
validate(response.getData()); // 若验证失败,抛出 RuntimeException
return Mono.just(response); // 验证通过,继续传递原始响应
} catch (Throwable t) {
return Mono.error(t); // 显式转为错误信号,确保可被重试机制识别
}
})
.retryWhen(Retry.backoff(3, Duration.ofSeconds(1)) // 可选:配合重试策略
.filter(throwable -> throwable instanceof RuntimeException));
}</response>
⚠️ 关键注意事项:
- ❌ 避免在 doOnNext、doOnSubscribe 等副作用操作符中抛出异常——它们设计用于“观察”,不参与流的数据/错误信号生成;
- ✅ flatMap 是执行有状态转换和条件分支的理想位置,支持返回 Mono.just() 或 Mono.error();
- ✅ Mono.error(Throwable) 是创建错误信号的标准方式,确保异常以 Reactive Streams 兼容的方式传播;
- ✅ 若使用 Spring 的 @Retryable,需确保异常类型匹配(如 RuntimeException),且方法调用处于 Spring AOP 代理范围内(通常要求类由 Spring 管理、非 private 方法);
- ? 如需更精细控制重试(如退避策略、忽略特定异常),优先使用 Reactor 原生 retryWhen() 而非仅依赖注解。
综上,显式抛出异常的本质不是“抛”,而是“发出错误信号”;通过 flatMap + Mono.error() 组合,既能保持响应式链的纯净性,又能精准触发重试与错误恢复逻辑。











