API组成部分
响应式流 JVM 规范由下列Reactive Streams接口组成:
- Publisher
- Subscriber
- Subscription
- Processor
Publisher 发布者会提供(可能)是无限多个元素,并按照 Subscriber 订阅者的处理速度进行发布(需求驱动)。
当调用 Publisher.subscribe(Subscriber) 后,有可能的 Subscriber 方法调用顺序为
onSubscribe onNext* (onError | onComplete)?
这代表 onSubscribe 始终会被调用,接下来是 0-N个 onNext 的事件;
当 onNext 调用结束后如果有错误会发送 onError 信号,若一切正常会发送 onComplete 通知下游没有更多元素了;
如果中途 Subscription 订阅被取消,那么可能 onError 和 onComplete 都不会被调用。
Publisher发布者
public interface Publisher<T> {
public void subscribe(Subscriber<? super T> s);
}
- Publisher发送给Subscriber的onNext信号总次数必须小于或等于Subscriber在当前Subscription中所请求的元素的个数。
这条规则确保Publisher不会发送多于Subscriber请求的元素个数,这样隐性地表达了一个happens-before的关系,
即请求元素发生在接收到元素之前。 - Publisher可以发送少于Subscriber请求的元素,并且通过发送onComplete或onError信号终止当前的Subscription。
这条规则声明Publisher并不能保证可以提供Subscriber所请求的元素个数,且原因可以是多样的(没有那么多元素,获取元素失败等等)。 - onSubscribe,onNext,onError和onComplete信号必须按照顺序进行发送。
这样确保在多线程的情况下能够确保信号之间的happens-before关系。 - 如果Publisher报错,那么它必须发送onError信号给Subscriber。
- 如果Publisher正常结束,那么它必须发送onComplete信号给Subscriber。
- 当Publisher向Subscriber发送了onError或onComplete信号后,当前Subscriber上的Subscription必须被视为已取消。
- 当订阅到达终结状态时(已发送onError或onComplete信号),Publisher不得再发布其他更多信号。
- 如果当前订阅Subscription已经被取消,那么相关的Subscriber最终必须停止被发送信号。
换句话说,当Subscription.cancel()被调用后,Subscriber仍有可能接收到一些元素,因为取消调用可能是异步发生的。 - Publisher.subscribe方法中必须先于其他方法调用Subscriber上的onSubscribe方法,并且必须正常返回(除了Subscriber为null值的情况)。
其他所有的异常情况都需要在onSubscribe调用结束后通过onError方法调用来通知订阅者。 - Publisher.subscribe方法可以被多次调用但每次都必须是一个不同的Subscriber。也就是相关的Publisher和Subscriber不能被关联多于一次。
- Publisher可以支持多个Subscriber并且自由决定当前的Subscription是单播unicast还是组播multicast。
Subscriber订阅者
public interface Subscriber<T> {
public void onSubscribe(Subscription s);
public void onNext(T t);
public void onError(Throwable t);
public void onComplete();
}
- Subscriber必须通过调用Subscription.request(long n)来传达自己的需求,这样确保由Subscriber来决定何时接收处理多少个onNext发送过来的元素。
- 如果Subscriber怀疑它对信号的处理会影响到Publisher的响应时,它应该确保发送信号的过程是异步的。
也就是说从线程执行的角度来讲,Subscriber的信号处理不应该影响Publisher的程序进度。 - Subscriber.onComplete()和Subscriber.onError(Throwable t)方法中不应该调用Subscription或Publisher上的任何方法,这样确保在处理终态信号时不会有竞态条件产生。
- 当Subscriber接收到onComplete或者onError(Throwable t)的调用后,它必须视当前的Subscription为已取消。
- 当Subscriber已经有了一个活跃的Subscription之后,跟其他Publisher之间的Subscription(在接收到onSubscribe信号后)必须通过调用Subscription.cancel()来取消。
因为在任何时候,一个Subscriber只能跟至多一个Publisher进行交互,多余的订阅必须被取消。 - 当Subscriber不再需要某个订阅时,必须调用该订阅上的cancel方法。
- Subscriber必须确保对Subscription上request(long n)和cancel()方法的调用是依次分开进行的,不能有时间上的重合(常见于多线程并发,需要用锁来确保资源独占)。
- Subscriber在调用了Subscription.cancel()之后仍要做好接收多个onNext信号的准备,因为仍有可能存在待处理的元素。
取消订阅操作不会保证立即执行清理操作。 - 即使前序没有Subscription.request(long n)的调用,Subscriber仍然要做好接收onComplete信号的准备。
- 即使前序没有Subscription.request(long n)的调用,Subscriber仍然要做好接收onError信号的准备,
因为Publisher的出错可能跟需求发送毫不相关。 - Subscriber必须确保所有的信号发送方法的调用发生在该信号对应的处理之前,
也就是Subscriber的实现需要保证异步处理时的线程安全。 - 对给定的Subscriber来讲,Subscriber.onSubscribe方法最多被调用一次。
- 与Publisher的第9条规则类似,调用Subscriber的onSubscribe,onNext, onError或onComplete方法必须正常返回(除非元素为null值);
如果Subscriber需要向Publisher表明自身的失败状态,必须通过取消订阅的操作来进行
Subscription订阅
public interface Subscription {
public void request(long n);
public void cancel();
}
- Subscription.request和Subscription.cancel必须在对应Subscriber的上下文中被调用。
这样是为了确保Subscription描述的是Subscriber和Publisher之间的唯一关联关系 - Subscription必须允许Subscriber在onNext或者onSubscribe中同步调用Subscription.request。
因为onNext可能是在request的栈帧上被调用,实际上也就是表明request必须是可重入的。 - Subscription.request必须为可能出现的Publisher和Subscriber间的同步递归调用设置上限,
以免出现栈溢出。 - Subscription.request应该即时返回,以免影响其调用者的响应。也就是说request线程上不应该执行复杂计算。
- Subscription.cancel应该即时返回,以免影响其调用者的响应,并且它也必须是线程安全和幂等的。
- 当Subscription被取消之后,任何额外的Subscription.request(long n)方法都应该是空操作。
- 当Subscription被取消之后,任何额外的Subscription.cancel()方法都应该是空操作。
- 当Subscription没有被取消时,Subscription.request(long n)必须指明subscriber在下一批请求中会注册多少个元素。
- 当Subscription没有被取消时,如果Subscription.request(long n)的入参n<0,那么必须调用onError来指定java.lang.IllegalArgumentException异常。
- 当Subscription没有被取消时,Subscription.request(long n)可以同步调用当前或其他Subscriber(s)的onNext方法。
- 当Subscription没有被取消时,Subscription.request(long n)可以同步调用当前或其他Subscriber(s)的onComplete或onError方法。
- 当Subscription没有被取消时,Subscription.cancel()必须要求Publisher最终停止发送元素给Subscriber。
- 当Subscription没有被取消时,Subscription.cancel()必须要求Publisher最终删除任何对当前Subscriber的对象引用。
- 当Subscription没有被取消时,调用Subscription.cancel()后可能会导致Publisher进入shut-down状态(如果它没有参与任何活跃的Subscription的话)。
- 调用Subscription.cancel()必须正常返回。
- 调用Subscription.request(long n)必须正常返回。
- 一个Subscription必须支持无限次调用request并且必须支持声明2^63-1(java.lang.Long.MAX_VALUE)个元素的需求。
- 如果请求的元素大于2^63-1,那么Publisher可以将它当作无穷多来处理(不再关注当前订阅的需求状态)。
Processor处理器
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
}
Processor代表一个处理中的状态,同时是一个Subscriber和Publisher,并且必须同时遵循二者的规范。
Processor可以尝试从onError信号中恢复状态。如果它这么做了,那么它必须将当前Subscription视为已取消,
否则它必须将onError信号传达给它的Subscribers。