Spring电抗器:Mono.zip在空Mono上失败

swvgeqrz  于 2022-11-21  发布在  Spring
关注(0)|答案(5)|浏览(197)

我正在使用Spring Reactor 3.1.0.M3,并且有一个用例,我需要合并来自多个源的Mono。我发现如果其中一个Mono是空Mono,zip会失败,并且没有错误。
示例:

Mono<String> m1 = Mono.just("A");
Mono<String> m2 = Mono.just("B");
Mono<String> m3 = Mono.empty();

Mono<String> combined = Mono.zip(strings -> {
    StringBuffer sb = new StringBuffer();
    for (Object string : strings) {
        sb.append((String) string);
    }
    return sb.toString();
}, m1, m2, m3);
System.out.println("Combined " + combined.block());

当添加m3时,响应为空时,组合子被跳过。当删除m3时,它按预期工作并返回“AB”。有没有办法通过检测空的Mono来处理这个问题?还有,有没有办法让组合子方法知道对象的类型,而不必强制转换?

68bkxrlz

68bkxrlz1#

zip运算符的行为不是这样的,它实际上是反直觉的:您的代码需要一个包含3个元素的元组,而您只得到了两个?!?
在这种情况下,您可以控制,只有您可以决定什么是一个好的默认值,如果没有提供(记住,null值是禁止的React流规范)。

Mono<String> m1 = Mono.just("A");
Mono<String> m2 = Mono.just("B");
Mono<String> m3 = Mono.empty().defaultIfEmpty("");

Mono<String> combined = Mono.zip(m1, m2, m3).map(t -> {
    StringBuffer sb = new StringBuffer();
    sb.append(t.getT1());
    sb.append(t.getT2());
    sb.append(t.getT3());
    return sb.toString();
});

编辑

您似乎被Publisher类型的性质所迷惑,请参阅:
如果其中一个Mono是空Mono,则压缩失败,没有错误

因此,如果我试图压缩Mono的,由于某种原因,其中一个是空的,压缩将失败,我似乎不能把任何代码来防止这种情况
空的Mono不是失败的情况:它只是没有发出任何值并且成功完成了。您可以通过更改代码示例来验证这一点:

combined.subscribe(
            s -> System.out.println("element: " + s), // doesn't execute
            s -> System.out.println("error: " + s), // doesn't execute
            () -> { System.out.println("complete!"); // prints
    });

因此,根据您的要求,您可以:

  • 如果有方便的默认值可以依赖,则在这3个Mono示例上应用defaultIfEmpty运算符
  • 在组合的Mono上应用defaultIfEmpty运算符,使用默认值,甚至将其转换为错误消息combined.switchIfEmpty(Mono.error(...))
q5iwbnjs

q5iwbnjs2#

String的情况下,为空的情况定义一个默认值是很容易的,这很好地解决了Brian的答案中所描述的问题。然而,对于其他自定义类型,由于这样或那样的原因,创建一个空对象可能很困难。这些情况下的一个替代方法是使用Optional。尽管这个解决方案有一些沉重的样板。

Mono<Optional<String>> m1 = Mono.just("A").map(Optional::of).defaultIfEmpty(Optional.empty());
Mono<Optional<String>> m2 = Mono.just("B").map(Optional::of).defaultIfEmpty(Optional.empty());
Mono<Optional<String>> m3 = Mono.<String>empty().map(Optional::of).defaultIfEmpty(Optional.empty());

Mono<String> combined = Mono.zip(strings -> {
    StringBuffer sb = new StringBuffer();
    for (Object string : strings) {
        ((Optional<String>) string).ifPresent(sb::append);
    }
    return sb.toString();
}, m1, m2, m3);
System.out.println("Combined " + combined.block());
zaq34kh6

zaq34kh63#

单声道压缩

任何源的错误或空完成将导致其他源被取消,并且产生的Mono分别立即错误或完成。
当一个Mono源代码在没有值的情况下完成时,如果您仍然希望继续执行其他源代码,那么Mono.zipDelayError是您的最佳选择。

cdmah0mi

cdmah0mi4#

应为Mono.zip

Mono<String> myStrings = Mono.zip(monoA, monoB)
  .map(tuple -> {
    return new StringBuffer()
      .append(t.getT1());
      .append(t.getT2());
});

同样,您可以传递Mono.just(Optional.empty()),而不是禁用nullMono.empty(),传递zip()

wsewodh2

wsewodh25#

完全公开,我的例子基本上是Brian Clozel的,但对其他数据类型进行了小的编辑以突出显示。

Mono<String> m1 = Mono.just("A");
Mono<String> m2 = Mono.just("B");
Mono<String> m3 = Mono.fromSupplier(() -> new String());

Mono<String> combined = Mono.zip(m1, m2, m3).map(t -> {
    StringBuffer sb = new StringBuffer();
    sb.append(t.getT1());
    sb.append(t.getT2());
    sb.append(t.getT3());
    return sb.toString();
});

例如,zip,将忽略空值的条目,例如Mono.empty。因此,要完成它,需要有一个非空值,在本例中是一个空字符串,但一个数据类型的新示例供您稍后在代码中检查也是不错的

相关问题