Spring Reactive中Mono异常为何无法被doOnError捕获?
1. 代码存在语法错误,doOnError未被正确加入流链路
你贴出的代码中doOnError调用存在明显的语法问题:
.doOnError(exe -> System.out.println("FAILURE! "+exe.getMessage());
doOnError方法的左括号没有对应的闭合右括号),如果实际运行的代码和你贴的一致,这行代码本身就无法正确将doOnError算子绑定到响应式流上,自然不会触发对应的逻辑。
2. 对doOnError的作用存在认知误区
就算你补上右括号修正语法问题,doOnError也不会「捕获、吞掉异常」。它本质是错误传播过程中的副作用钩子:仅在错误信号流经该算子位置时,执行你定义的附加逻辑(比如打日志、上报监控),执行完成后错误信号会继续向下游传播,不会终止。
你调用subscribe时只传入了处理正常元素的System.out::println,没有传入错误处理回调。当错误最终传播到流的订阅末端时,Reactor发现没有定义错误消费逻辑,就会抛出Exceptions$ErrorCallbackNotImplemented异常,把错误直接抛到运行线程。
补充:修正语法后你其实能看到
doOnError里的打印语句输出,你之前没观察到,大概率是语法问题导致算子未生效,或者测试框架拦截异常时控制台输出顺序让你忽略了已打印的内容。
Reactor的异常是基于响应式流信号传播的,和命令式编程的try-catch逻辑不同,不要用try-catch直接包裹subscribe调用(仅能捕获流组装阶段的同步异常,无法捕获运行阶段异步传播的错误信号),正确处理方式分两类:
1. 流中间处理:错误恢复/转换
这类算子会真正消费错误信号,终止错误向下传播,根据错误返回 fallback 逻辑,让流继续走正常分支:
onErrorReturn:出错时直接返回固定默认值Mono.defer(() -> myMethod()) .onErrorReturn("请求失败,返回默认值") .subscribe(System.out::println);onErrorResume:出错时切换到自定义的备用响应式流,实现更灵活的降级逻辑Mono.defer(() -> myMethod()) .onErrorResume(exe -> { System.out.println("执行降级逻辑,错误信息:" + exe.getMessage()); return Mono.just("降级返回值"); // 也可以返回Mono.error()包装成其他异常继续抛出 }) .subscribe(System.out::println);onErrorMap:捕获当前错误,包装成自定义业务异常后继续向下传播
2. 订阅末端处理:消费最终错误
subscribe提供了多参数重载,第二个入参就是专门的错误消费回调,只要传入该回调,错误到了订阅端就会被消费,不会再向外抛出异常:
public void errorProcessor() { Mono.defer(()-> myMethod()) // doOnError仅用来做打日志、埋点这类和业务无关的副作用操作 .doOnError(exe -> System.out.println("监控埋点:接口调用失败,"+exe.getMessage())) .subscribe( data -> System.out.println("正常返回结果:" + data), // 处理正常元素 err -> System.out.println("末端捕获错误,执行兜底逻辑:" + err.getMessage()) // 消费错误,不会再抛异常 ); }
注意:永远不要用
doOnError做业务错误恢复逻辑,它不会中断错误传播,仅适合做无状态的附加操作。
内容的提问来源于stack exchange,提问作者Factor Three

