在 Reactor 编程模型中,需通过 Mono.error() 显式触发错误信号以激活重试逻辑;避免在 doOnNext 中抛出异常(因其不改变数据流),应改用 flatMap 进行校验并可控地返回成功或错误的 Mono。
在 reactor 编程模型中,需通过 `mono.error()` 显式触发错误信号以激活重试逻辑;避免在 `doonnext` 中抛出异常(因其不改变数据流),应改用 `flatmap` 进行校验并可控地返回成功或错误的 mono。
在响应式编程中,Mono 是一个异步、非阻塞的单值发布者,其错误处理机制与传统同步代码有本质区别:不能依赖 throw 语句直接中断流,因为这会抛出未捕获的运行时异常(如 OnErrorNotImplementedException),而非向下游传播标准错误信号。要实现“校验失败即触发重试”的目标,关键在于将业务校验逻辑嵌入到流式操作链中,并通过 Mono.error() 主动发射错误信号。
正确做法是使用 flatMap —— 它允许你根据上游值动态返回一个新的 Mono,从而灵活控制后续流向:
public Mono<Response> handleResponse() {
return userService.getUser()
.flatMap(response -> {
try {
validate(response.getData()); // 若校验失败,抛出 RuntimeException
return Mono.just(response); // 校验通过,继续正常流
} catch (RuntimeException e) {
return Mono.error(e); // 显式转为错误信号,触发 @Retryable 或 retry() 逻辑
}
})
.retry(3); // 可选:手动配置重试次数(若未使用 Spring Retry 注解)
}⚠️ 注意事项:
- ❌ 避免在 doOnNext、doOnSuccess 等副作用操作中抛出异常——它们仅用于观测,不参与流控制,抛出异常会导致流意外终止且难以调试;
- ✅ flatMap 是校验+分支决策的理想选择:它天然支持“值→Mono”的映射,可安全封装 try/catch 并分别返回 Mono.just() 或 Mono.error();
- ✅ 若使用 Spring 的 @Retryable 注解(如题中所示),确保该方法被 Spring AOP 正确代理(即调用需来自其他 Bean,而非本类内部直接调用),且异常类型与注解配置严格匹配(如 RuntimeException.class);
- ? Mono.retry()、retryWhen() 等操作符可替代注解实现声明式重试,更契合纯 Reactor 场景,例如:.retryWhen(Retry.backoff(3, Duration.ofSeconds(1)))。
总结:Reactor 的错误传播必须基于信号(onError),而非指令式异常。用 flatMap + try/catch + Mono.error() 替代 doOnNext + throw,是实现可预测、可重试的响应式校验的标准实践。

















