提升开发效率,降低维护成本一直是开发团队永恒不变的宗旨。近两年来国内的技术圈子中越来越多的开始提及ReactiveX,越来越多的应用和面试中都会有ReactiveX,响应式编程中RxJava可谓如鱼得水。
目录
1. 背景
2. 响应式编程是什么
2.1 原理简析
2.3 与传统观察者模式不同
2.2 Rx是Push还是Pull
3. 优势 & 代价
4. Reactive Streams规约
4.1 Publisher
4.2 Subscriber
4.3 Subscription
4.4 Processor
5. 主流实现
5.1 Rx2.x
5.2 Reactive Stream
5.3 Java9
5.4 Spring WebFlux
5.5 Vertx
前面提到过是为了提升开发效率,代码质量(简洁),降低维护成本。
注:异步操作很关键的一点是程序的简洁性,因为在调度过程比较复杂的情况下,异步代码经常会既难写也难被读懂。
响应式编程是一种基于异步数据流概念的编程模式。数据流就像一条河:它可以被观测,被过滤,被操作,或者为新的消费者与另外一条流合并为一条新的流。响应式编程的一个关键概念是事件。事件可以被等待,可以触发过程,也可以触发其它事件。
Rx提供了一系列的操作符,你可以使用它们来过滤(filter)、选择(select)、变换(transform)、结合(combine)和组合(compose)多个Observable,这些操作符让执行和复合变得非常高效。
响应式流从2013年开始,作为提供非阻塞背压的异步流处理标准的倡议。它旨在解决处理元素流的问题——如何将元素流从发布者传递到订阅者,而不需要发布者阻塞,或订阅者有无限制的缓冲区或丢弃。
在2015年,出版了用于处理响应式流的规范和Java API。请访问http://www.reactive-streams.org/ 。
Rx 的异步实现,是通过一种扩展的观察者模式来实现的。程序的观察者模式和这种真正的『观察』略有不同,观察者不需要时刻盯着被观察者(例如 A 不需要每过 2ms 就检查一次 B 的状态),而是采用注册(Register)或者称为订阅(Subscribe)的方式,告诉被观察者:我需要你的某某状态,你要在它变化的时候通知我。
如上图可以引出Rx的一些重要概念:
Observable(被观察者)可以理解为数据源、数据发射器,Observer(观察者)针对行为事件数据做出的响应。Observable
和 Observer
通过 subscribe()
方法实现订阅关系,从而 Observable
可以在需要的时候发出事件来通知 Observer
。
RxJava 的事件回调方法除了普通事件 onNext (相当于 onClick / onEvent)之外,还定义了两个特殊的事件:onCompleted 和 onError。
为何需要会多两个onCompleted/onError呢?
Observable为了更贴近有Iterable类型操作一致,添加了两种缺少的语义:
响应式流模型非常简单——订阅者向发布者发送多个元素的异步请求。 发布者向订阅者异步发送多个或稍少的元素。响应式流在pull模型和push模型流处理机制之间动态切换。 当订阅者较慢时,它使用pull模型,当订阅者更快时使用push模型。
你可以把Observable当做Iterable的推送方式的等价物,可以理解为:所有使用Iterable的地方都可以使用Rx(上面也提过),
事件 |
Iterable(pull) |
Observable(push) |
获取数据 |
|
|
异常处理 |
throws |
|
任务完成 |
|
|
//伪代码:
// Iterable
getDataFromLocalMemory()
.skip(10)
.take(5)
.map({ s -> return s + " transformed" })
.forEach({ println "next => " + it });
// Observable
getDataFromNetwork()
.skip(10)
.take(5)
.map({ s -> return s + " transformed" })
.subscribe({ println "onNext => " + it });
总之,Observable是异步的双向push,Iterable是同步的单向pull。
优势
代价
是潜在无限数量的有序元素的生产者。 它根据收到的要求向当前订阅者发布(或发送)元素
从发布者那里订阅并接收元素。 发布者向订阅者发送订阅令牌(subscription token)。 使用订阅令牌,订阅者从发布者哪里请求多个元素。 当元素准备就绪时,发布者向订阅者发送多个或更少的元素。 订阅者可以请求更多的元素。 发布者可能有多个来自订阅者的元素待处理请求。
表示订阅者订阅的一个发布者的令牌。 当订阅请求成功时,发布者将其传递给订阅者。 订阅者使用订阅令牌与发布者进行交互,例如请求更多的元素或取消订阅。
充当订阅者和发布者的处理阶段。Processor
订阅类型T的数据元素,接收并转换为类型R的数据,并发布变换后的数据,该接口继承了Publisher
和Subscriber
接口。
RxJava是响应式流的Java实现之一,而RxJava 2.0 已经按照Reactive-Streams specification规范完全的重写了。
Reactor 2.0.0.RC1 于2015年02月19日由Pivotal RTI(Spring 框架发起者)发布,支持 Reactive Stream,它的构架总览:
注:上图参考附录Reactor指南中文版,Reactor1.x实在是不太出名,也是规范没出来吧
Reactor 代码库拆分成多个子模块,便于选择所需功能,不受其他功能代码块干扰。
下面举例说明,为实现异步目标,响应式技术和 Reactor 模块该如何搭配:
与Rx2.x的差异:
RxJava |
reactor-stream |
说明 |
Observable |
reactor.rx.Stream |
Reactive Stream Publisher的实现 |
Operator |
reactor.rx.action.Action |
Reactive Stream Processor的实现 |
Observable with 1 data at most |
reactor.rx.Promise |
返回唯一结果的类型, Reactive Stream Processor实现并提供了可选的异步分发功能。 |
Factory API (just, from…) |
reactor.rx.Streams |
和core模块的 data-focused 子类一样, 返回 Stream |
Functional API (map, filter…) |
reactor.rx.Stream |
和core模块的data-focused 子类一样, 返回Stream |
Schedulers |
reactor.core.Dispatcher, org.reactivestreams.Processor |
Reactor Stream计算无限制的共享Dispatcher或者有限的Processor的操作。 |
Observable.observeOn() |
Stream.dispatchOn() |
只是dispatcher参数的一个适配命名。 |
JDK 9 java.util.concurrent 包提供了两个主要的 API 来处理响应流:
Spring WebFlux 是 Spring 5 的一个新模块,包含了响应式 HTTP 和 WebSocket 的支持,在容器中 Spring WebFlux 会将输入流适配成 Mono 或者 Flux 格式进行统一处理。,另外在上层服务端支持两种不同的编程模型:
- 基于 Spring MVC 注解 @Controller 等
- 基于 Functional 函数式路由
为啥只能运行在 Servlet 3.1+ 容器?3.1 规范其中一个新特性是异步处理支持。
Vert.x是一个异步无阻塞的网络框架,其参照物是node.js。基本上node.js能干的事情,Vert.x都能干。Vert.x利用Netty4的EventLoop来做单线程的事件循环,所以跑在Vert.x上的业务不能做CPU密集型的运算,这样会导致整个线程被阻塞。
Vert.x目前是见过功能最强大(core、web、Data access、reacive、microservices、MQTT),第三方库依赖最少的Java框架,它只依赖Netty4以及Jacskon,另外如果你需要建立分布式的Vert.x则再依赖HazelCast这个分布式框架,注意Vert.x3必须基于Java8。
总结,响应式编程已经慢慢成我我们开发中的主流,后续将带您深入了解《rxjava》