为什么Mono.error(OutOfMemoryError)搭配thenReturn会向订阅线程抛出异常
原理说明
这个现象本质是Reactor 3.4.3版本中致命异常判定规则和同步融合优化共同作用的结果,具体逻辑如下:
首先明确Reactor的致命异常判定规则:
Reactor核心工具类Exceptions.isFatal(Throwable t)会将VirtualMachineError(包含OutOfMemoryError、StackOverflowError等JVM层面的致命错误)判定为需要直接透传抛出的异常,普通自定义Error不属于该范畴。其次是
thenReturn操作符的同步融合特性:
3.4.3版本的thenReturn操作符支持**同步融合(Synchronous Fusion)**优化,当上游是立即生成结果/异常的同步Publisher(比如你代码中的Mono.error(...))时,上下游会达成融合模式,thenReturn不会被动等待上游发送onNext/onError信号,而是直接调用上游Subscription的poll()方法主动拉取结果。异常直接抛出的核心逻辑:
融合模式下,上游MonoError的poll()方法会直接抛出持有的异常。如果抛出的是OutOfMemoryError这类致命异常,Reactor的融合处理逻辑不会将其捕获转换为onError信号,而是直接透传到调用栈上层,最终落到订阅线程。其他场景不会抛出的原因:
- 直接订阅
Mono.error(new OutOfMemoryError("hello world")):没有融合类操作符参与,走正常的信号传递流程,OOM会被封装为onError信号传递给默认订阅者,默认订阅者只会打印错误日志,不会把异常抛到订阅线程。 - 调用
then()之后再执行thenReturn:then()操作符不支持同步融合,直接打断了融合链,下游thenReturn无法和最上游的MonoError达成融合模式,OOM走正常的onError信号传递链路,不会直接抛出。 - 使用普通
Error:普通Error不属于致命异常,就算在融合模式下被poll()抛出,Reactor也会主动捕获它转换为onError信号传递,不会透传到订阅线程。
- 直接订阅
内容的提问来源于stack exchange,提问作者Pete Gillin
相关产品推荐
相关产品推荐

