反应式编程 RxJava 设计原理解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 本篇文章主要聚焦对RxJava中几种主要的设计模式的理解,通过梳理Observable的相关类图以及讲解这些类之间的关系,让大家能够更清晰的理解RxJava中事件驱动的工作原理。

本文首发于 vivo互联网技术 微信公众号 
链接:https://mp.weixin.qq.com/s/duO1pAfaKUI2_x_GVvZHMg
作者:Yunjie Ma

一、ReactiveX 与 RxJava

ReactiveX 的全称为Reactive Extension,一般缩写为 Rx,即我们平常所说的反应式编程。其设计原理主要使用了观察者模式,区分数据的生产者和消费者,通过事件流的方式进行数据的异步处理。

RxJava 是 ReactiveX Java语言的实现,其编程体验与Java 8中的函数式编程和流(Stream)有很大的相似之处,在掌握了Java8的相关知识后,你可以很轻松的就上手使用 RxJava。

本篇文章主要聚焦对RxJava中几种主要的设计模式的理解,通过梳理Observable的相关类图以及讲解这些类之间的关系,让大家能够更清晰的理解RxJava中事件驱动的工作原理。

二、RxJava中的概念

首先我们写一个简单的RxJava的程序,把数组中的元素作为事件发送,最终由消费者打印在控制台:

我们以这段简单的代码为基础,讲解下贯穿整个ReactiveX设计的四个概念:观察者,被观察者,事件,订阅

  • 观察者:对事件进行响应的对象,也可以称作消费者,在上述的代码中,subscirbe方法的参数是一个Consumer对象,该对象后续会被包装成一个LambdaObserver对象,即为这段代码中的观察者(消费者)。

  • 被观察者:产生事件的对象,也可以称作生产者,在上述代码中,Observable.fromArray(...)返回的是一个Observable对象,即为这段程序的被观察者(生产者)。

  • 事件:RxJava中存在四种事件流:onSubscribe(订阅事件),onNext(正常事件),onError(异常事件),onComplete(完成事件)。在上述代码中,是将数组中的元素作为onNext事件中的数据进行发送。

  • 订阅:创建观察者与被观察者之间观察关系,对应着上述代码中的subscribe()方法。RxJava的事件驱动模型是一种“拉模型”,在观察者没有进行事件订阅之前是不会有事件产生的,只有观察者进行订阅后,才会触发被观察者生产事件。

对上述代码进行时序分析,可以清晰的看出这一段代码的运行过程,最终由FromArrayDisposable生产了onNext和onComplete事件,并通知Observer进行消费。

与此同时,我们也看到,简单的一行代码,竟然涉及这么多类的交互,如果增加一些其他的操作符,我们对整个程序把控起来就没那么容易了,下面我们将通过分析RxJava中的一些主要的设计模式,剖析类与类的关联关系,来更清晰地理解RxJava的工作原理。

三、 集大成者Observable

在整个数据处理的过程中,Observable可以说是最重要的一个对象。从上面的时序图可以看出,客户端(消息的生产者或者消费者)只和Observable进行交互,观察者和被观察者之间关系的创建也是由Observable去实现,而不用我们显示的编码实现,这大大降低了我们使用观察者模式的成本。

那么Observable主要有哪些作用呢,我们首先来看下和Observable相关的类图:

从图中我们可以看出:

  • Observable实现了ObservableSource接口,从字面意思就可以理解,这是一个提供观察能力的接口,所以Observable的一大能力是供观察者进行事件订阅,而进行事件订阅的方法实现就是调用Observable的subscribe()方法

  • Observable是一个抽象类,它提供了subscribeActual模板方法供子类实现,从源码中可以看出,Observable的subscribe()方法最终会委托子类的subscribeActual()方法实现,这个方法会建立生产者与消费者之间的关联关系。

  • 除此之外,Observable还是一个工厂类,它提供了静态方法fromArray()、create()等用来创建具体的可观察对象,同时还提供了flatMap()、concatMap()等操作方法对可观察对象进行包装。

Observable的存在让生产者和消费者完全的解耦了,生产者只需关注自己生成何种Observable对象,而消费者也只需关注自己观察的是哪种Observable。

在实际的应用中,Rxjava已经提供了各种各样的操作符供我们使用,生产者只需要调用Observable中相应的方法即可以生成所需的可观察对象,供消费者进行事件订阅。消费者只需调用可观察对象的subscribe()方法即可与生产者建立观察关系,极其方便。

四、 真实的观察

观察者模式是RxJava设计的核心思想,在观察者模式中总是存在观察的对象和被观察的对象,从上文的解析中也可以看出Observable更多的是一个控制器的作用,而并非真正的事件的来源。那么在RxJava中,什么才是真正的生产者,什么才是真正的消费者呢。

我们来分析下以下三种常见的Observable:

先简单介绍下这几个Observable的作用,fromArray的作用是将数组中的元素作为onNext事件发送,create的作用是发送自定义事件,just的作用是发送单个事件。

上一小节有讲到实际的订阅行为是由各个Observable类中subscribeActual()方法实现的,我们来看下这三个类的subscribeActual()方法。

除去细枝末节,这三个方法都可以分成以下三步

  1. 创建被观察者对象,并传入观察者observer,建立两者的关联关系;

  2. 触发onSubscribe事件,观察者响应该事件;

  3. 进行事件的拉取,我们可以进入到d.run(),source.subscribe(parent),sd.run()这些方法的内部看一些,可以看到这些方法就是在发送onNext(),onError(),onComplete()等事件。

下图是整个流程中的相关类图。实际事件的发送者是FromArrayDisposable等对象,而实际的观察者,则是一个实现了Observer接口的实体类。如果我们在subscribe时传入的是一个lambda表达式,之后会被包装成一个默认的LambdaObserver对象,进行事件消费。

五、 包装的必要

RxJava中提供了丰富的操作符,比如flatMap,concatMap等可以对事件转换,subscribeOn,observableOn等可以对生产和消费的线程进行控制。这些操作符实际上调用了Observable中的包装方法对原有的可观察对象进行包装,返回了一个增强了的可观察对象。

操作符种类繁多,在这就不一一举例,我们以flatMap为例,分析一下这些操作符是如何工作的。

首先,flatMap操作会返回一个ObservableFlatMap对象,在创建这个对象时,会将原始的Observable对象作为构造函数的参数传入。

查看其核心方法subscribeActual,

可以看到这一类对象的subscribeActual方法和上一节中的方法不太一样,这里面并没有去实际的创建观察关系,而是做了两件事:

  1. 对观察者进行增强,将其包装成为MergeObserver对象,由其对产生的时间进行响应。

  2. 再调用source的subscribe方法,这里source就是前面构造函数中传入的Observable对象,由其再进行观察关系的建立。

    下图是RxJava中装饰器模式的相关类图:所有的包装类都继承了AbstractObservableWithUpstream类,该抽象类有一个类型为ObservableSource的成员函数,用来持有被装饰的对象。
    
    

Observable是支持链式操作的,就和Java 8中的Stream一样,我们来考虑这样一行代码。

我们在分析上面这串代码时,一定会凌乱非常,在看源码时也会看到前面忘掉后面,但是如果我们对RxJava的包装流程足够了解的话,就可以很轻松的对上述代码进行分析。

六、 小结

RxJava的封装足够强大,可以让我们很方便的进行使用和扩展,但这也给我们理解其真实的工作原理带来了难度,如果我们对整个事件的处理过程处于一知半解的状态,那我们就无法从容的对服务进行异步编排,在实际开发过程中也难以发现问题的根源。

本文主要分析了RxJava中主要的设计模式,其中有模板模式、工厂模式、观察者模式、装饰器模式,理解了这些设计模式,理解了RxJava中类与类的关系,我们就能够对整个事件的处理流程了然于胸,分析代码时也能够事半功倍。

目录
相关文章
|
3天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
15 3
|
6天前
|
Java 关系型数据库 MySQL
【编程基础知识】Eclipse连接MySQL 8.0时的JDK版本和驱动问题全解析
本文详细解析了在使用Eclipse连接MySQL 8.0时常见的JDK版本不兼容、驱动类错误和时区设置问题,并提供了清晰的解决方案。通过正确配置JDK版本、选择合适的驱动类和设置时区,确保Java应用能够顺利连接MySQL 8.0。
41 1
|
8天前
|
Java
【编程基础知识】《Java 基础探秘:return、break、continue、label、switch 与 enum 的深度解析》
本文深入解析了 Java 中的 return、break、continue、label、switch 和 enum 等基础概念,通过代码示例和流程图,帮助读者理解这些控制结构和枚举类型在编程中的应用,提升编程能力。
17 3
|
8天前
|
Java
【编程基础知识】《Java 中的神秘利器:this 关键字深度解析》
《Java 中的神秘利器:this 关键字深度解析》深入探讨了 Java 中 this 关键字的作用、用法及应用场景。文章详细解释了 this 如何指向当前对象、区分成员变量和局部变量、调用构造函数、实现方法链式调用和传递当前对象。通过阅读本文,读者将全面掌握 this 关键字的巧妙应用,提升 Java 编程技能。
17 2
|
8天前
|
开发框架 Oracle Java
【编程基础知识】《Java 世界探秘:JRE、JDK 与 JDK 版本全解析》
JRE(Java Runtime Environment)是运行Java程序所需的环境,包含JVM和Java核心类库,适合普通用户使用。JDK(Java Development Kit)则是Java开发工具包,不仅包含JRE,还提供了编译器、调试器等开发工具,适用于开发者。两者的主要区别在于JDK用于开发,而JRE仅用于运行Java程序。JDK各版本不断引入新特性,如Java 8中的Lambda表达式和默认方法等。环境配置方面,Windows和Linux系统都有详细的步骤,确保Java程序能够顺利编译和运行。
18 1
|
15天前
|
前端开发 Java 应用服务中间件
21张图解析Tomcat运行原理与架构全貌
【10月更文挑战第2天】本文通过21张图详细解析了Tomcat的运行原理与架构。Tomcat作为Java Web开发中最流行的Web服务器之一,其架构设计精妙。文章首先介绍了Tomcat的基本组件:Connector(连接器)负责网络通信,Container(容器)处理业务逻辑。连接器内部包括EndPoint、Processor和Adapter等组件,分别处理通信、协议解析和请求封装。容器采用多级结构(Engine、Host、Context、Wrapper),并通过Mapper组件进行请求路由。文章还探讨了Tomcat的生命周期管理、启动与停止机制,并通过源码分析展示了请求处理流程。
|
12天前
|
开发框架 缓存 前端开发
electron-builder 解析:你了解其背后的构建原理吗?
本文首发于微信公众号“前端徐徐”,详细解析了 electron-builder 的工作原理。electron-builder 是一个专为整合前端项目与 Electron 应用的打包工具,负责管理依赖、生成配置文件及多平台构建。文章介绍了前端项目的构建流程、配置信息收集、依赖处理、asar 打包、附加资源准备、Electron 打包、代码签名、资源压缩、卸载程序生成、安装程序生成及最终安装包输出等环节。通过剖析 electron-builder 的原理,帮助开发者更好地理解和掌握跨端桌面应用的构建流程。
36 2
|
5天前
|
前端开发 JavaScript UED
axios取消请求CancelToken的原理解析及用法示例
axios取消请求CancelToken的原理解析及用法示例
14 0
|
6天前
|
设计模式 SQL 安全
【编程进阶知识】Java单例模式深度解析:饿汉式与懒汉式实现技巧
本文深入解析了Java单例模式中的饿汉式和懒汉式实现方法,包括它们的特点、实现代码和适用场景。通过静态常量、枚举类、静态代码块等方式实现饿汉式,通过非线程安全、同步方法、同步代码块、双重检查锁定和静态内部类等方式实现懒汉式。文章还对比了各种实现方式的优缺点,帮助读者在实际项目中做出更好的设计决策。
22 0
|
8天前
|
存储 缓存 数据处理
深度解析:Hologres分布式存储引擎设计原理及其优化策略
【10月更文挑战第9天】在大数据时代,数据的规模和复杂性不断增加,这对数据库系统提出了更高的要求。传统的单机数据库难以应对海量数据处理的需求,而分布式数据库通过水平扩展提供了更好的解决方案。阿里云推出的Hologres是一个实时交互式分析服务,它结合了OLAP(在线分析处理)与OLTP(在线事务处理)的优势,能够在大规模数据集上提供低延迟的数据查询能力。本文将深入探讨Hologres分布式存储引擎的设计原理,并介绍一些关键的优化策略。
37 0

推荐镜像

更多