Flux.just(1, 2, 3)
.doOnNext(__ -> System.out.println("producing number: " + __))
.publish()
.autoConnect()
.doOnNext((Integer __) -> {
System.out.println("throwing error.");
throw new RuntimeException("aaa");
})
.retry(1, error -> true)
.subscribe(number -> System.out.println("I will never be here..."),
error -> System.out.println("will I be here? " + error),
() -> System.out.println("completed!"));
输出:
producing number: 1
throwing error.
producing number: 2
producing number: 3
预期的输出:(根据我的逻辑-我确定我弄错了)
producing number: 1
throwing error.
producing number: 2
throwing error.
producing number: 3
为什么输出不同于预期的输出?
答案 0 :(得分:2)
这有点棘手,但归结为:
调用publish
和autoConnect
的效果是,一旦您订阅,就会创建一个内部订阅,即使取消外部订阅,该内部订阅也会保留。可以将其视为由publish
和autoConnect
连接的两个流。
--inner stream--> publish/connect-> --outer stream--> subscriber
无论外部流发生什么,内部流将继续运行。这是因为您有一个热门观察站,并且可能有多个订阅者。如果一个断开连接,则其他连接仍然希望从流中获得值。换句话说,发布运算符告诉源代码,它可以根据需要生成值。
--inner stream--> publish/connect-> --outer stream--> subscriber1
--outer stream--> subscriber2
您可以通过删除retry
来验证该行为。数字1和2仍将被打印。如果希望源停止产生值,则可以使用refCount
代替autoConnect
。如果没有更多订阅者,refCount
将取消内部流。
这是棘手的部分:该流是同步的,Streams are just functions。实际情况要复杂一些,但是retry运算符内部的subscription函数将运行,直到内部流完成为止。只有这样,它才能重新订阅。
与异步流不同,例如由Flux.interval
创建。
Flux.interval(Duration.ofSeconds(1))
.doOnNext(__ -> System.out.println("producing number: " + __))
.publish()
.autoConnect()
.doOnNext((Integer __) -> {
System.out.println("throwing error.");
throw new RuntimeException("aaa");
})
.retry(1)
.subscribe()
当您呼叫.subscribe()
时,retry
将在doOnNext
上内部呼叫订阅,依此类推,直到Flux上的第一个doOnNext
呼叫subscribe
为止。间隔Flux说“好吧,我会在一秒钟内发出第一个值”,并且订阅已建立。
一秒钟后,发出一个值,引发错误,重试运算符再次订阅。
在您的示例中,在完全建立订阅之前,Flux已经开始在订阅调用期间发出值,可以这么说。