
在 Reactor 中,若需在 Mono 处理过程中主动触发异常(如数据校验失败时),应避免在 doOnNext 等副作用操作中抛出异常,而应使用 Mono.error() 构造错误信号,并配合 flatMap 实现可控的错误传播,从而被 @Retryable 或原生 retryWhen 正确捕获与重试。
在 reactor 中,若需在 mono 处理过程中主动触发异常(如数据校验失败时),应避免在 `doonnext` 等副作用操作中抛出异常,而应使用 `mono.error()` 构造错误信号,并配合 `flatmap` 实现可控的错误传播,从而被 `@retryable` 或原生 `retrywhen` 正确捕获与重试。
在响应式编程中,Mono 的设计强调不可变性与声明式错误传播:任何中间操作(如 doOnNext、doOnError)都属于“副作用”(side-effect),其唯一职责是执行日志、监控或轻量验证,绝不应改变流的信号类型(即不能将 onNext 转为 onError)。否则会导致未预期的行为——例如你在 doOnNext 中抛出 RuntimeException,该异常会被 Reactor 捕获并封装为 OnErrorNotImplementedException,而非你期望的原始异常类型,导致 @Retryable 注解无法匹配重试条件。
✅ 正确做法是使用 flatMap 将每个 onNext 信号转换为一个新的 Mono,并在其中显式控制成功路径(Mono.just(...))或失败路径(Mono.error(...)):
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); // 显式转为 onError 信号
}
})
.retryWhen(Retry.backoff(3, Duration.ofSeconds(1))
.filter(throwable -> throwable instanceof RuntimeException)); // 可选:精细化重试策略
}</response>
⚠️ 注意事项:
- validate() 方法应只负责业务逻辑校验,不处理流控制;
- Mono.error(t) 是构造错误信号的标准方式,确保异常作为 onError 信号向下传递,可被 @Retryable(需配合 Spring Retry + Reactor 集成)或原生 retryWhen 正确识别;
- 避免使用 Exceptions.propagate() 或 throw 在非 flatMap/handle 等可返回 Mono 的操作中——这会破坏响应式契约;
- 若使用 Spring 的 @Retryable,请确保方法返回 Mono 且配置了 ReactorRetryTemplate 或启用 @EnableRetry 与 RetryTemplate 的 Reactor 适配器。
总结:响应式流中的“显式抛错”,本质是用 Mono.error() 主动发出错误信号,而非传统阻塞式 throw。选择 flatMap 作为转换入口,既保持函数式风格,又赋予你对每个元素的完全控制权——这是实现可重试、可观测、符合 Reactive Streams 规范的最佳实践。











