我对RxJava很陌生,并且 - 正如其他许多人一样 - 我正在努力解决异常处理问题。我在网上阅读了不少帖子(例如此处的讨论how to handle exceptions thrown by observer's onNext)和认为我已经了解了概念的基本概念。
在上述讨论中,其中一张海报说,当订阅者抛出异常时,RxJava会执行以下操作:
实施通用处理以记录失败并停止向其发送事件 (任何类型的)并清理由于该订户而携带的任何资源 任何剩余的订阅。
这或多或少都是我看到的,我唯一遇到的问题是"清理任何资源"位。为清楚起见,我们假设以下示例:
我想创建一个Observable,它在每个收到的消息上监听异步事件源(例如JMS队列)和onNext()。所以在(伪)代码中我会做类似的事情:
Observable<String> observable = Observable.create( s -> {
createConnectionToBroker();
getConsumer().setMessageListener(message -> s.onNext(transform(message)));
s.setDisposable(new Disposable() {
public void dispose() {
tearDownBrokerConnection();
}
});
});
由于我想为许多订阅者/观察者重用消息监听器,我不直接订阅创建的Observable,而是使用publish()。refCount()团队。类似的东西:
Observable<String> observableToSubscribeTo = observable.publish().refCount();
Disposable d1 = observableToSubscribeTo.subscribe(s -> ...);
Disposable d2 = observableToSubscribeTo.subscribe(s -> ...);
这一切都按预期工作。代码仅在第一个订阅建立时连接到JMS,并且当最后一个观察者为dispose()
时,与代理的连接将关闭。
然而,当订阅者在onNext()
时抛出异常时,事情似乎变得混乱。正如预期的那样,投掷的观察者已经被激活,每当发布新事件时,它都不会再被通知。我的问题似乎是当所有剩余订户都为dispose()
d时,不再通知维护与消息代理的连接的Observable。它看起来好像抛出异常的订阅者处于某种僵尸状态。它在事件分发时会被忽略,但它会以某种方式阻止根Observable在最后一个订阅者dispose()
d时收到通知。
我理解RxJava希望观察者确保不会抛出,而是正确处理最终异常。不幸的是,在我想提供一个向调用者返回一个Observable的库的情况下,我无法控制我的订阅者。这意味着,我永远无法保护我的图书馆免受愚蠢的观察者的侵害。
所以,我问自己:我在这里错过了什么吗?当用户抛出时,真的没有机会正确清理吗?这是一个错误还是只是我不理解图书馆?
任何见解都非常感谢!
答案 0 :(得分:1)
如果你能展示一些能够证明问题(不需要JMS)的单元测试,那就太棒了。
此外,RxJava 2中的onNext永远不会抛出;如果它确实是一个未定义的行为。如果您不信任您的消费者,您可以使用safeSubscribe
而不是普通subscribe
的终端可观察变换器,以增强对下游行为不端的保护:
.compose(o -> v -> o.safeSubscribe(v))
或
.compose(new ObservableTransformer<T>() {
@Override public Observable<T> apply(final Observable<T> source) {
return new Observable<T>() {
@Override public void subscribeActual(Observer<? super T> observer) {
source.safeSubscribe(observer);
}
};
}
})