如何通过日志区分Mono.error(Throwable)与Mono.error(Supplier<? extends Throwable>)的差异?
如何通过日志区分Mono.error(Throwable)与Mono.error(Supplier<? extends Throwable>)的差异?
嗨,这个问题问得好!其实只要抓住「异常创建时机」这个核心点,用日志就能一目了然地区分这两种Mono.error的差异。我给你一步步演示怎么操作:
第一步:自定义带构造日志的异常类
我们先写一个异常,在它的构造函数里打印日志,这样就能精准追踪异常什么时候被创建:
public class LoggedException extends RuntimeException { public LoggedException() { super(); // 打印构造时机+线程信息,方便定位 System.out.println("[异常构造] LoggedException 实例化于线程: " + Thread.currentThread().getName()); } }
第二步:分别测试两种Mono.error方式
接下来我们写两个测试方法,分别验证eager(立即创建)和lazy(延迟创建)的行为:
测试 eager 模式:Mono.error(Throwable)
public static void testEagerError() { System.out.println("=== 测试 Eager 模式 ==="); // 注意:这里创建Mono的瞬间,异常就已经被实例化了! Mono.error(new LoggedException()) .doOnSubscribe(sub -> System.out.println("[订阅事件] 开始订阅 Mono")) .subscribe( value -> System.out.println("收到值: " + value), error -> System.out.println("[订阅完成] 捕获异常: " + error.getClass().getSimpleName()) ); }
它的输出日志顺序会是这样:
[异常构造] LoggedException 实例化于线程: main
[订阅事件] 开始订阅 Mono
[订阅完成] 捕获异常: LoggedException
看,异常在创建Mono对象的时候就已经生成了,甚至比订阅操作还要早!这就是所谓的eager加载。
测试 lazy 模式:Mono.error(Supplier<? extends Throwable>)
public static void testLazyError() { System.out.println("\n=== 测试 Lazy 模式 ==="); // 这里只是传入了Supplier,异常还没被创建 Mono.error(LoggedException::new) .doOnSubscribe(sub -> System.out.println("[订阅事件] 开始订阅 Mono")) .subscribe( value -> System.out.println("收到值: " + value), error -> System.out.println("[订阅完成] 捕获异常: " + error.getClass().getSimpleName()) ); }
它的输出日志顺序会是:
=== 测试 Lazy 模式 ===
[订阅事件] 开始订阅 Mono
[异常构造] LoggedException 实例化于线程: main
[订阅完成] 捕获异常: LoggedException
这里异常是在订阅触发之后才被构造的——只有当Mono需要发送错误信号时,才会调用Supplier创建异常对象,这就是lazy加载的核心。
第三步:额外验证多次订阅的差异
如果我们多次订阅同一个Mono,差异会更明显:
public static void testMultipleSubscriptions() { System.out.println("\n=== 测试多次订阅 ==="); // Eager模式:异常只创建一次 Mono<Throwable> eagerMono = Mono.error(new LoggedException()); System.out.println("--- 第一次订阅 Eager Mono ---"); eagerMono.subscribe(); System.out.println("--- 第二次订阅 Eager Mono ---"); eagerMono.subscribe(); // Lazy模式:每次订阅都创建新的异常实例 Mono<Throwable> lazyMono = Mono.error(LoggedException::new); System.out.println("--- 第一次订阅 Lazy Mono ---"); lazyMono.subscribe(); System.out.println("--- 第二次订阅 Lazy Mono ---"); lazyMono.subscribe(); }
对应的日志里,Eager模式只会打印1次[异常构造],而Lazy模式会打印2次——因为每次订阅都会触发Supplier创建新的异常对象。
总结一下
要通过日志区分这两种方式,核心就是追踪异常的构造时机:
Mono.error(Throwable):异常在Mono创建时立即生成,日志会早于订阅事件Mono.error(Supplier):异常在订阅触发(需要发送错误信号时)才生成,日志晚于订阅事件;多次订阅会生成多个异常实例
备注:内容来源于stack exchange,提问作者Gagan
相关产品推荐
相关产品推荐

