首页 > 解决方案 > Spring Reactive - 重用 Mono 值

问题描述

我有一系列Mono使用flatMap. 我设法将我的生产代码简化为这个测试用例:

@Test
public void test() {
    AtomicInteger iCounter = new AtomicInteger(1);
    Mono<String> iValueMono = Mono.fromSupplier(() -> {
        int iValue = iCounter.getAndIncrement();
        System.out.println("iValueMono CALL: " + iValue);
        return String.valueOf(iValue);
    });

    Mono<String> resultMono = Mono.just("X")
            .flatMap(append(iValueMono))
            .flatMap(append(iValueMono));

    StepVerifier.create(resultMono)
            .consumeNextWith(result -> assertThat(result).isEqualTo("X11"))
            .expectComplete()
            .verify();
}

private Function<String, Mono<String>> append(Mono<String> sMono) {
    return s -> sMono.map(v -> s + v);
}

这打印:

iValueMono CALL: 1
iValueMono CALL: 2

org.junit.ComparisonFailure: 
Expected :"X11"
Actual   :"X12"

我想——我现在知道这是不正确的——每次我iValueMonoappend()调用中映射时,供应商都会重新执行以产生一个新值。我无法在生产代码中更改它的iValueMono实现方式(例如,使其有状态来存储值)。我怎样才能实现这一点,以便只调用一次价值供应商并且我得到最终结果“X11”?

当然,我对一种非阻塞的、反应式的方法很感兴趣。

标签: javaspringspring-webfluxproject-reactor

解决方案


使用Mono.cache()是答案:

将此 Mono 转换为热源并缓存最后发出的信号以供后续订阅者使用。

使用它:

Mono<String> iValueMono = Mono.fromSupplier(() -> {
    int iValue = iCounter.getAndIncrement();
    System.out.println("iValueMono CALL: " + iValue);
    return String.valueOf(iValue);
}).cache();

只需致电供应商一次即可提供所需的结果。


推荐阅读