\

要点

\\

  • Reactor是一个运行在Java8之上的响应式流框架,它提供了一组响应式风格的API\\t
  • 除了个别API上的区别,它的原理跟RxJava很相似\\t
  • 它是第四代响应式框架,支持操作融合,类似RxJava 2\\t
  • Spring 5的响应式编程模型主要依赖Reactor\

\\

RxJava回顾

\\

Reactor是第四代响应式框架,跟RxJava 2有些相似。Reactor项目由Pivotal启动,以响应式流规范、Java8和ReactiveX术语表为基础。它的设计是Reactor 2(上一个主要版本)和RxJava核心贡献者共同努力的结果。

\\

在之前的同系列文章“RxJava实例解析”和“测试RxJava”里,我们已经了解了响应式编程的基础:数据流的概念、Observable类和它的各种操作以及通过工厂方法创建静态和动态的Observable对象。

\\

Observable是事件的源头,Observer提供了一组简单的接口,并通过订阅事件源来消费Observable的事件。Observable通过onNext向Observer通知事件的到达,后面可能会跟上onError或onComplete来表示事件的结束。

\\

RxJava提供了TestSubscriber来测试Observable,TestSubscriber是一个特别的Observer,可以用它断言流事件。

\\

在这篇文章里,我们将会对Reactor和RxJava进行比较,包括它们的相同点和不同点。

\\

Reactor的类型

\\

Reactor有两种类型,Flux\u0026lt;T\u0026gt;和Mono\u0026lt;T\u0026gt;。Flux类似RaxJava的Observable,它可以触发零到多个事件,并根据实际情况结束处理或触发错误。

\\

Mono最多只触发一个事件,它跟RxJava的Single和Maybe类似,所以可以把Mono\u0026lt;Void\u0026gt;用于在异步任务完成时发出通知。

\\

因为这两种类型之间的简单区别,我们可以很容易地区分响应式API的类型:从返回的类型我们就可以知道一个方法会“发射并忘记”或“请求并等待”(Mono),还是在处理一个包含多个数据项的流(Flux)。

\\

Flux和Mono的一些操作利用了这个特点在这两种类型间互相转换。例如,调用Flux\u0026lt;T\u0026gt;的single()方法将返回一个Mono\u0026lt;T\u0026gt;,而使用concatWith()方法把两个Mono串在一起就可以得到一个Flux。类似地,有些操作对Mono来说毫无意义(例如take(n)会得到n\u0026gt;1的结果),而有些操作只有作用在Mono上才有意义(例如or(otherMono))。

\\

Reactor设计的原则之一是要保持API的精简,而对这两种响应式类型的分离,是表现力与API易用性之间的折中。

\\

“使用响应式流,基于Rx构建”

\\

正如“RxJava实例解析”里所说的,从设计概念方面来看,RxJava有点类似Java 8 Steams API。而Reactor看起来有点像RxJava,不过这决不只是个巧合。这样的设计是为了能够给复杂的异步逻辑提供一套原生的具有Rx操作风格的响应式流API。所以说Reactor扎根于响应式流,同时在API方面尽可能地与RxJava靠拢。

\\

响应式类库和响应式流的使用

\\

Reactive Streams(以下简称为RS)是“一种规范,它为基于非阻塞回压的异步流处理提供了标准”。它是一组包含了TCK工具套件和四个简单接口(Publisher、Subscriber、Subscription和Processor)的规范,这些接口将被集成到Java 9.

\\

RS主要跟响应式回压(稍后会详细介绍)以及多个响应式事件源之间的交互操作有关。它并不提供任何操作方法,它只关注流的生命周期。

\\

Reactor不同于其它框架的最关键一点就是RS。Flux和Mono这两者都是RS的Publisher实现,它们都具备了响应式回压的特点。

\\

在RxJava 1里,只有少部分操作支持回压,RxJava 1的Observable并没有实现RS里的任何类型,不过它有一些RS类型的适配器。可以说,RxJava 1实际上比RS规范出现得更早,而且在RS规范设计期间,RxJava 1充当了函数式工作者的角色。

\\

所以,你在使用那些Publisher适配器时,它们并不会为你提供任何操作。为了能做一些有用的操作,你可能需要用回Observable,而这个时候你需要另一个适配器。这种视觉上的混乱会破坏代码的可读性,特别是像Spring 5这样的框架,如果整个框架建立在这样的Publisher之上,那么就更是杂乱不堪。

\\

RS规范不支持null值,所以在从RxJava 1迁移到Reactor或RxJava 2时要注意这点。如果你在代码里把null用作特殊用途,那么就更是要注意了。

\\

RxJava 2是在RS规范之后出现的,所以它直接在Flowable类型里实现了Publisher。不过除了RS类型,RxJava 2还保留了RxJava 1的“遗留”类型(Observable、Completable和Single)并且引入了其它一些可选类型——Maybe。这些类型提供了不同的语义,不过它们并没有实现RS接口,这是它们的不足之处。跟RxJava 1不一样,RxJava 2的Observable不支持RxJava 2的回压协议(只有Flowable具备这个特性)。之所以这样设计是为了能够为一些场景提供一组丰富且流畅的API,比如用户界面发出的事件,在这样的场景里是不需要用到回压的,而且也不可能用到。Completable、Single和Maybe不需要支持回压,不过它们也提供了一组丰富的API,而且在被订阅之前不会做任何事情。

\\

在响应式领域,Reactor变得愈加精益,它的Mono和Flux两种类型都实现了Publisher,并且都支持回压。虽然把Mono作为一个Publisher需要付出一些额外的开销,不过Mono在其它方面的优势弥补了它的缺点。在后续部分我们将看到对Mono来说回压意味着什么。

\\

相比RxJava,API相似但不相同

\\

ReactiveX和RxJava的操作术语表有时候真的难以掌握,因为历史原因,有些操作的名字让人感到困惑。Reactor尽量把API设计得紧凑,在给API取名时尽量选择好一点的名字,不过总的来说,这两套API看起来还是很相像。在最新的RxJava 2迭代版本中,RxJava 2借鉴了Reactor的一些术语,这预示着这两个项目之间可能会有越来越紧密的合作。一些操作和概念总是先出现在其中的一个项目里,然后互相借鉴,最后会同时渗透到两个项目里。

\\

例如,Flux也有常见的just工厂方法(虽然只有两种变形:接受一个参数或变长参数)。不过from方法有很多个变种,最值得一提的是fromIterable。当然,Flux也包含了那些常规的操作:map、merge、concat、flatMap、take,等等。

\\

Reactor把RxJava里令人困惑的amb操作改成了看起来更加中肯的firstEmitting。另外,为了保持API的一致,toList被重新命名为collectList。实际上,所有以collect开头的操作都会把值聚合到一个特定类型的集合里,不过只会为每个集合生成一个Mono。而所有以to开头的操作被保留用于类型转换,转换之后的类型可以用于非响应式编程,例如toFuture()。

\\

在类初始化和资源使用方面,Reactor之所以也能表现得如此精益,要得益于它的融合特性:Reactor可以把多个串行的操作(例如调用concatWith两次)合并成单个操作,这样就可以只对这个操作的内部类做一次初始化(也就是macro-fusion)。这个特性包含了基于数据源的优化,抵消了Mono在实现Publisher时的一些额外开销。它还能在多个相关的操作之间共享资源(也就是micro-fusion),比如内部队列。这些特性让Reactor成为不折不扣的的第四代响应式框架,不过这个超出了这篇文章的讨论范围。

\\

下面让我们来看看几个Reactor的操作。

\\

一些操作示例

\\

(这一小节包含了一些代码片段,我们建议你动手去运行它们,深入体验一下Reactor。所以你需要打开IDE,并创建一个测试项目,把Reactor加入到依赖项里。)

\\

对于Maven,可以把下面的依赖加到pom.xml里:

\\

\\u0026lt;dependency\u0026gt;\    \u0026lt;groupId\u0026gt;io.projectreactor\u0026lt;/groupId\u0026gt;    \    \u0026lt;artifactId\u0026gt;reactor-core\u0026lt;/artifactId\u0026gt;\    \u0026lt;version\u0026gt;3.0.3.RELEASE\u0026lt;/version\u0026gt;\\u0026lt;/dependency\u0026gt;

\\

对于Gradle,要把Reactor作为依赖项,类似这样:

\\

\dependencies {\    compile \"io.projectreactor:reactor-core:3.0.3.RELEASE\"\}

\\

我们来重写前面几篇同系列文章里的例子!

\\

Observable的创建跟在RxJava里有点类似,在Reactor里可以使用just(T...)和fromIterator(Iterable\u0026lt;T\u0026gt;)工厂方法来创建。just方法会把List作为一个整体触发,而fromIterable会逐个触发List里的每个元素:

\\

\public class ReactorSnippets {\  private static List\u0026lt;String\u0026gt; words = Arrays.asList(\        \"the\

Reactor实例解析相关推荐

  1. List元素互换,List元素转换下标,Java Collections.swap()方法实例解析

    Java Collections.swap()方法解析 jdk源码: public static void swap(List<?> list, int i, int j) {// ins ...

  2. python argparse模块_Python argparse模块应用实例解析

    这篇文章主要介绍了Python argparse模块应用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 简介 argparse是python ...

  3. php的延迟绑定,PHP延迟静态绑定使用方法实例解析

    这篇文章主要介绍了PHP延迟静态绑定使用方法实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 PHP的继承模型中有一个存在已久的问题,那就是在 ...

  4. 实例解析linux内核I2C体系结构

    实例解析linux内核I2C体系结构 一.概述 谈到在linux系统下编写I2C驱动,目前主要有两种方式,一种是把I2C设备当作一个普通的字符设备来处理,另一种是利用linux I2C驱动体系结构来完 ...

  5. python反射实例化_Python类反射机制使用实例解析

    这篇文章主要介绍了Python类反射机制使用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 反射就是通过字符串的形式,导入模块:通过字符串的 ...

  6. JavaWeb实现文件上传下载功能实例解析

    转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web应用系统开发中,文件上传和下载功能是非常常用的功能 ...

  7. python的用途实例-python进程池作用展示及实例解析

    在以下的文章之中我们来了解一下什么是python中的进程池.了解一下python进程池的相关知识,以及进程池在python编程之中能起到什么样的作用. 进程池 Pool类描述了一个工作进程池,他有几种 ...

  8. python pandas读取excel-Python使用Pandas读写Excel实例解析

    这篇文章主要介绍了Python使用Pandas读写Excel实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Pandas是python的一个 ...

  9. python image 转成字节_(推荐)谈谈Python生态圈图像格式转换问题:含实例解析

    今天为大家带来的内容是:(推荐)谈谈Python生态圈图像格式转换问题:含实例解析 天气冷了,码字手都不利索了!先哈一哈气,各位也要多穿衣服注意保暖哈.话不多说,就直接进入主题了. 在Python生态 ...

最新文章

  1. 通过 vSphere WS API 获取 vCenter Datastore Provisioned Space 置备空间
  2. 利用css3实现jQuery中的slideDown和slideUp效果
  3. python基础语法第10关作业-【python基础语法】第11天作业练习题
  4. Java 中日期的几种常见操作 —— 取值、转换、加减、比较
  5. golang平滑重启
  6. LeetCode - Easy - 118. Pascal‘s Triangle
  7. 使用Symantec Altiris 来监控 Dell 服务器 的 硬件
  8. 第一章:Shiro简介
  9. 施乐悄悄修复影响某些打印机中的严重缺陷
  10. 如何让你的Python程序支持多语言
  11. HTC手机如何进行官方解锁Unlock
  12. 重庆金域 :新系统成功上线!重庆金域第一份新系统的报告单2017年9月21日13:00正式发出
  13. 部分一二线城市的建筑物矢量图
  14. 代理(proxy):正向代理,反向代理
  15. 神经系统疾病题库【1】
  16. MySQL数据库11——子查询语句
  17. JQuery加载图片自适应DIV大小
  18. 使用ADO创建Excel数据表
  19. 『已解决』.NET报错:所生成项目的处理器框架“MSIL”与引用“wdapi_dotnet1021”的处理器架构“AMD64”不匹配
  20. ij idea(2021)的jdk版本可能和本地的有冲突

热门文章

  1. 立刻停止使用AUFS,开启Overlay!
  2. mysql5.7 不复制多张表
  3. 《javascript模式》 容易踩中的那些坑
  4. springboot 使用 redis 管理session
  5. 【干货分享】可能是东半球最全的.NET Core跨平台微服务学习资源
  6. git 基本操作语句
  7. EXP-00091错误的说明和解决方法
  8. BZOJ1295 [SCOI2009]最长距离
  9. PowerDesigner打开设计文件后提示failed to read the fileXXX的解决办法
  10. Devexpress 10.2.3 Demo 批量生成脚本