You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过日志区分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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 09:44:28