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

Reactor中getMono1与getMono3执行差异及日志顺序问题

响应式编程基础疑问:Mono执行差异与日志顺序解析

我是响应式编程新手,希望理解相关基础概念。以下是测试代码:

@Test
public void testMonoThen() {
    Mono<Void> fromRunnable = Mono.fromRunnable(() -> log.info("message from main"));
    fromRunnable.then(getMono1()).then(getMono2()).subscribe();

    //vs

    Mono<Void> fromRunnable2 = Mono.fromRunnable(() -> log.info("message from main2"));
    fromRunnable2.then(getMono3()).then(getMono4()).subscribe();
    
}

public Mono<Void> getMono1() {
    return Mono.fromRunnable(
            () -> log.info("Message from thread: {} and method mono1", Thread.currentThread().getId()));
}

public Mono<Void> getMono2() {
    return Mono.fromRunnable(
            () -> log.info("Message from thread: {} and method mono2", Thread.currentThread().getId()));
}

public Mono<Void> getMono3() {
    log.info("Message from thread: {} and method mono3", Thread.currentThread().getId());
    return Mono.empty();
}

public Mono<Void> getMono4() {
    log.info("Message from thread: {} and method mono4", Thread.currentThread().getId());
    return Mono.empty();
}

对应的输出为:

19:07:10.971 [main] DEBUG reactor.util.Loggers - Using Slf4j logging framework
19:07:10.977 [main] INFO com.reactivetests.SampleTest - message from main
19:07:10.977 [main] INFO com.reactivetests.SampleTest - Message from thread: 1 and method mono1
19:07:10.979 [main] INFO com.reactivetests.SampleTest - Message from thread: 1 and method mono2
19:07:10.980 [main] INFO com.reactivetests.SampleTest - Message from thread: 1 and method mono3
19:07:10.981 [main] INFO com.reactivetests.SampleTest - Message from thread: 1 and method mono4
19:07:10.981 [main] INFO com.reactivetests.SampleTest - message from main2

请问从执行角度来看,getMono1和getMono3函数存在哪些差异?为何日志输出顺序不一致,比如message from main的打印顺序不符合预期?


一、getMono1与getMono3的核心执行差异

  • 执行时机完全不同
    • getMono1:日志逻辑被包裹在Mono.fromRunnable()中,属于延迟执行。只有当订阅触发,且上游Mono(fromRunnable)执行完成后,这部分日志才会被Reactor调度执行。
    • getMono3:日志直接写在方法体内,属于立即执行。只要调用getMono3方法(哪怕还没调用subscribe),这行日志就会同步打印出来,完全不受响应式流的生命周期控制。
  • 是否属于响应式流环节
    • getMono1的日志是响应式流水线的一部分,执行顺序由Reactor的流控制逻辑决定。
    • getMono3的日志是普通同步代码,脱离了响应式流的管理,等同于调用一个普通Java方法时立刻执行的逻辑。

二、日志顺序不符合预期的原因

拆解代码执行的实际流程:

  1. 第一部分代码执行流程:
    调用subscribe()后,先触发fromRunnable里的log.info("message from main")打印;上游Mono完成后,才会触发getMono1返回的Mono执行,打印mono1日志;接着上游完成后触发getMono2的Mono执行,打印mono2日志。这部分完全遵循响应式流的顺序执行。
  2. 第二部分代码执行流程:
    在调用fromRunnable2.then(getMono3())时,getMono3方法会被立即同步调用,所以先打印mono3的日志;紧接着调用then(getMono4()),getMono4方法也被立即调用,打印mono4的日志;最后调用subscribe(),才会触发fromRunnable2里的log.info("message from main2")执行,所以这条日志出现在最后。

本质原因:getMono3/getMono4的方法体代码是在构建响应式流水线阶段同步执行的,而getMono1/getMono2的逻辑是被包装在Mono内部,只有订阅后流走到对应环节才会触发执行。

内容的提问来源于stack exchange,提问作者Harsha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 21:12:06