Java Reactor.then()不会等到所有项目发出后才开始处理

Java Reactor.then()不会等到所有项目发出后才开始处理,java,spring-webflux,project-reactor,Java,Spring Webflux,Project Reactor,我试图打印一个从doOnNext()函数递增的计数器 public static void main(String [] args) { final AtomicInteger counter = new AtomicInteger(); Mono.just(List.of(1)) .doOnNext(i -> System.out.println("doOnNext " + counter.inc

我试图打印一个从doOnNext()函数递增的计数器

    public static void main(String [] args) {
        final AtomicInteger counter = new AtomicInteger();
        Mono.just(List.of(1))
                .doOnNext(i -> System.out.println("doOnNext " + counter.incrementAndGet()))
                .map(i -> {
                    System.out.println("map " + counter.get());
                    return i;
                })
                .then(thenFunction(counter))
                .block();
    }

    private static Mono<Integer> thenFunction(final AtomicInteger counter) {
        System.out.println("then " + counter.get());
        return Mono.just(2);
    }
then()不应该等到上游完成后再处理吗


我使用的是spring boot starter webflux
2.3.8。在您的示例中,在构建流的过程中,在组装阶段调用
thenFunction
方法。因此,
System.out.println(“then”+counter.get())在元素开始流经流之前被调用

要将
thenFunction
中的逻辑延迟到订阅时间,您可以将
thenFunction
调用包装在
Mono.defer
中,如下所示:

.then(Mono.defer(()->thennfunction(counter)))
或者,(首选)您可以使函数在内部延迟其逻辑,直到订阅返回的Mono,如下所示:

私有静态函数(最终原子整数计数器){
返回Mono.fromCallable(()->{
System.out.println(“then”+counter.get());
返回2;
});
}

啊!这是很好的洞察力。只有一个问题,为什么您更喜欢Mono.fromCallable()而不是Mono.defer()?看起来后一个函数看起来更干净,它们实现了相同的功能(在下游订阅时触发supplier函数)@KetoneManiac,因为一个是热发布者,另一个是冷发布者,所以如果我理解正确,最好使用Mono.fromCallable(),它本身就是冷发布者,我认为更普遍的建议是遵循“订阅前一切都不会发生”的被动原则,而不是先创建一个热门的发布服务器(Mono.just(2)),然后明确地将其设置为冷发布服务器(Mono.defer())。将逻辑放在组装阶段发生的反应式方法(而不仅仅是构建流)中会导致灾难。您不仅会得到您提到的奇怪行为,而且还失去了利用一些有价值的弹性操作符的能力,如
.timeout
.retry*
。repeat*
,因为这些操作符不会影响汇编时间逻辑。
then 0
doOnNext 1
map 1