执行多个反应操作的正确方法

A53*_*300 5 spring-webflow spring-data-mongodb project-reactor

我从反应式存储库中获取Mono<FooBar>基于它的值,我必须创建另外两个对象,使用反应式存储库保存它们,修改FooBar对象并保存它。

由于我是反应式编程的新手,我使用了以下解决方案,该解决方案有效,但我不确定我是否正确使用了反应式 API:

@Test
void createAndSave() {
    Mono<FooBar> fooBarMono = findFooBar()  // returns Mono<FooBar>
            .map(fooBar -> {
        createAndSaveLoremBar(fooBar).subscribe();   // returns Mono<LoremBar>
        createAndSaveDoloremBar(fooBar).subscribe(); // returns Mono<DoloremBar>

        fooBar.setActive(true);

        return saveFooBar(fooBar);          // returns Mono<FooBar>
    }).flatMap(Function.identity());

    StepVerifier.create(fooBarMono)
            .expectNextMatches(Objects::nonNull)
            .expectComplete()
            .verify();

}
Run Code Online (Sandbox Code Playgroud)

从控制台日志:

   saved lorem bar
   saved dolorem bar
   saved foo bar
Run Code Online (Sandbox Code Playgroud)

pio*_*cki 7

我认为下面的解决方案更具可读性。无论如何,亚历山大是正确的,你永远不应该修改输入。你看,我们借用了函数式编程的很多概念。例如你称Function.identity()这个为 identity functor. 和Flux都是Mono单子。对于这些人来说,有一个秘密的概念称为Referential transparency强制更新中断。

    final Mono<FooBar> fooBarMono1 = findFooBar()
            .zipWhen((fooBar) -> createAndSaveLoremBar(fooBar))
            .map(tuple -> tuple.getT1())
            .zipWhen((fooBar) -> createAndSaveDoloremBar(fooBar))
            .map(tuple -> tuple.getT1())
            .map(fooBar -> new FooBar(true))
            .flatMap(fooBar -> saveFooBar(fooBar));
Run Code Online (Sandbox Code Playgroud)

或者更简洁:

    final Mono<FooBar> fooBarMono1 = findFooBar()
            .zipWhen((fooBar) -> createAndSaveLoremBar(fooBar)
                                    .then(createAndSaveDoloremBar(fooBar)))
            .map(tuple -> tuple.getT1())
            .map(fooBar -> new FooBar(true))
            .flatMap(fooBar -> saveFooBar(fooBar));
Run Code Online (Sandbox Code Playgroud)


Ale*_*kin 4

首先,在异步(反应式)世界中改变对象并不是一个好主意。

无论如何,在您的解决方案中,可能会忽略 lorem 和 dolorem 保存上的错误。您可以像这样改进它:

Mono<FooBar> fooBarMono = findFooBar()
        .flatMap(fooBar -> Flux.merge(
                createAndSaveLoremBar(fooBar),
                createAndSaveDoloremBar(fooBar)) // asynchronously saving lorem and dolorem
                .then(Mono.fromCallable(() -> {  // if there wasn't errors, mutate and save fooBar
                    fooBar.setActive(true);
                    return fooBar;
                }).flatMap(fooBar1 -> saveFooBar(fooBar1))));
Run Code Online (Sandbox Code Playgroud)

fooBar如果您可以创建带有 true标志的副本active,代码可能会更简单。例如龙目岛。

@Builder(toBuilder = true)
public class FooBar {
...
}

Mono<FooBar> fooBarMono = findFooBar()
        .flatMap(fooBar -> Flux.merge(
                createAndSaveLoremBar(fooBar),
                createAndSaveDoloremBar(fooBar))
                .then(saveFooBar(fooBar.toBuilder().active(true).build())));
Run Code Online (Sandbox Code Playgroud)

如果您对结果不感兴趣,saveFooBar(...)而只对完成信号感兴趣,则可以异步进行所有三个保存:

Flux<Object> flux = findFooBar()
        .flatMapMany(fooBar -> Flux.merge(
                createAndSaveLoremBar(fooBar),
                createAndSaveDoloremBar(fooBar),
                saveFooBar(fooBar.toBuilder().active(true).build())));
Run Code Online (Sandbox Code Playgroud)

实际上,在最后一种方法中,您可以收集所有三个结果,并且您应该更喜欢这种方法,但我没有关于您的类和创建完整示例的要求的足够信息。