命令式与反应式
在开发应用程序代码时,我们可以编写两种风格的代码,即命令式和反应式。
命令式(Imperative)的代码:它由一组任务组成,每次只运行一项任务,每项任务又都依赖于前面的任务。数据会按批次进行处理,在前一项任务还没有完成对当前数据批次的处理时,不能将这些数据递交给下一项处理任务。
反应式(Reactive)的代码:它定义了一组用来处理数据的任务,但是这些任务可以并行地执行。每项任务处理数据的一部分子集,并将结果交给处理流程中的下一项任务,同时继续处理数据的另一部分子集。
Reactor 是一个反应式编程库,同时也是Spring家族的一部分。它是Spring 5反应式编程功能的基础。
反应式编程概览
反应式编程是一种可以替代命令式编程的编程范式。这种可替代性存在的原因在于反应式编程解决了命令式编程中的一些限制。理解这些限制,有助于你更好地理解反应式编程模型的优点。
反应式编程本质上是函数式的和声明式的。相对于描述一组将依次执行的步骤,反应式编程描述了数据将会流经的管道或者流。相对于要求将被处理的数据作为一个整体进行处理,反应式流可以在数据可用时立即开始处理。实际上,传入的数据可能是无限的。
定义
反应式流(Reactive Streams)是由Netflix、Lightbend和Pivotal(Spring背后的公司)的工程师于2013年年底开始制定的一种规范。反应式流旨在提供无阻塞回压的异步流处理标准。
反应式编程的异步特性,使我们能够并行执行任务,从而实现更高的可伸缩性。通过回压,数据消费者可以限制它们想要处理的数据数量,避免被过快的数据源所淹没。
Java的流和反应式流
Java的流通常都是同步的,并且只能处理有限的数据集。从本质上来说,它们只是使用函数来对集合进行迭代的一种方式。
反应式流支持异步处理任意大小的数据集,同样也包括无限数据集。只要数据就绪,它们就能实时地处理数据,并且能够通过回压来避免压垮数据的消费者。
反应式流的规范
反应式流规范可以总结为4个接口:Publisher、Subscriber、Subscription和Processor。
Publisher负责生成数据,并将数据发送给 Subscription(每个Subscriber对应一个Subscription)。Publisher接口声明了一个方法 subscribe(),Subscriber可以通过该方法向 Publisher发起订阅。
public interface Publisher<T> {
void subscribe(Subscriber<? super T> subscriber);
}
一旦Subscriber订阅成功,就可以接收来自Publisher的事件。这些事件是通过Subscriber接口上的方法发送的:
public interface Subscriber<T> {
void onSubscribe(Subscription sub);
void onNext(T item);
void onError(Throwable ex);
void onComplete();
}
Subscriber的第一个事件是通过对 onSubscribe()方法的调用接收的。Publisher调用 onSubscribe() 方法时,会将Subscription对象传递给 Subscriber。通过Subscription,Subscriber可以管理其订阅情况:
public interface Subscription {
void request(long n);
void cancel();
}
Subscriber可以通过调用 request()方法来请求 Publisher 发送数据,或者通过调用 cancel()方法表明它不再对数据感兴趣并且取消订阅。当调用 request()时,Subscriber 可以传入一个long类型的数值以表明它愿意接受多少数据。这也是回压能够发挥作用的地方,以避免Publisher 发送多于 Subscriber能够处理的数据量。在Publisher发送完所请求数量的数据项之后,Subscriber可以再次调用 request()方法来请求更多的数据。
Subscriber 请求数据之后,数据就会开始流经反应式流。Publisher 发布的每个数据项都会通过调用Subscriber 的 onNext()方法递交给 Subscriber。如果有任何错误,就会调用 onError()方法。如果 Publisher 没有更多的数据,也不会继续产生更多的数据,那么将会调用 Subscriber 的onComplete()方法来告知Subscriber 它已经结束。
至于Processor接口,它是Subscriber和Publisher的组合:
public interface Processor<T, R>
extends Subscriber<T>, Publisher<R> {}
当作为 Subscriber时,Processor会接收数据并以某种方式对数据进行处理。然后它会将角色转变为Publisher,并将处理的结果发布给它的Subscriber。
反应式流规范的接口本身并不支持以函数式的方式组成这样的流。Reactor项目是反应式流规范的一个实现,提供了一组用于组装反应式流的函数式API。