天天看點

反應式程式設計 RxJava 設計原了解析

作者:閃念基因

一、ReactiveX 與 RxJava

ReactiveX 的全稱為Reactive Extension,一般縮寫為 Rx,即我們平常所說的反應式程式設計。其設計原理主要使用了觀察者模式,區分資料的生産者和消費者,通過事件流的方式進行資料的異步處理。

RxJava 是 ReactiveX Java語言的實作,其程式設計體驗與Java 8中的函數式程式設計和流(Stream)有很大的相似之處,在掌握了Java8的相關知識後,你可以很輕松的就上手使用 RxJava。

本篇文章主要聚焦對RxJava中幾種主要的設計模式的了解,通過梳理Observable的相關類圖以及講解這些類之間的關系,讓大家能夠更清晰的了解RxJava中事件驅動的工作原理。

二、RxJava中的概念

首先我們寫一個簡單的RxJava的程式,把數組中的元素作為事件發送,最終由消費者列印在控制台:

反應式程式設計 RxJava 設計原了解析

我們以這段簡單的代碼為基礎,講解下貫穿整個ReactiveX設計的四個概念:觀察者,被觀察者,事件,訂閱。

  • 觀察者:對事件進行響應的對象,也可以稱作消費者,在上述的代碼中,subscirbe方法的參數是一個Consumer對象,該對象後續會被包裝成一個LambdaObserver對象,即為這段代碼中的觀察者(消費者)。
  • 被觀察者:産生事件的對象,也可以稱作生産者,在上述代碼中,Observable.fromArray(...)傳回的是一個Observable對象,即為這段程式的被觀察者(生産者)。
  • 事件:RxJava中存在四種事件流:onSubscribe(訂閱事件),onNext(正常事件),onError(異常事件),onComplete(完成事件)。在上述代碼中,是将數組中的元素作為onNext事件中的資料進行發送。
  • 訂閱:建立觀察者與被觀察者之間觀察關系,對應着上述代碼中的subscribe()方法。RxJava的事件驅動模型是一種“拉模型”,在觀察者沒有進行事件訂閱之前是不會有事件産生的,隻有觀察者進行訂閱後,才會觸發被觀察者生産事件。
反應式程式設計 RxJava 設計原了解析

對上述代碼進行時序分析,可以清晰的看出這一段代碼的運作過程,最終由FromArrayDisposable生産了onNext和onComplete事件,并通知Observer進行消費。

與此同時,我們也看到,簡單的一行代碼,竟然涉及這麼多類的互動,如果增加一些其他的操作符,我們對整個程式把控起來就沒那麼容易了,下面我們将通過分析RxJava中的一些主要的設計模式,剖析類與類的關聯關系,來更清晰地了解RxJava的工作原理。

三、 集大成者Observable

在整個資料處理的過程中,Observable可以說是最重要的一個對象。從上面的時序圖可以看出,用戶端(消息的生産者或者消費者)隻和Observable進行互動,觀察者和被觀察者之間關系的建立也是由Observable去實作,而不用我們顯示的編碼實作,這大大降低了我們使用觀察者模式的成本。

那麼Observable主要有哪些作用呢,我們首先來看下和Observable相關的類圖:

反應式程式設計 RxJava 設計原了解析

從圖中我們可以看出:

  • 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:

反應式程式設計 RxJava 設計原了解析

先簡單介紹下這幾個Observable的作用,fromArray的作用是将數組中的元素作為onNext事件發送,create的作用是發送自定義事件,just的作用是發送單個事件。

上一小節有講到實際的訂閱行為是由各個Observable類中subscribeActual()方法實作的,我們來看下這三個類的subscribeActual()方法。

反應式程式設計 RxJava 設計原了解析

除去細枝末節,這三個方法都可以分成以下三步

  1. 建立被觀察者對象,并傳入觀察者observer,建立兩者的關聯關系;
  2. 觸發onSubscribe事件,觀察者響應該事件;
  3. 進行事件的拉取,我們可以進入到d.run(),source.subscribe(parent),sd.run()這些方法的内部看一些,可以看到這些方法就是在發送onNext(),onError(),onComplete()等事件。

下圖是整個流程中的相關類圖。實際事件的發送者是FromArrayDisposable等對象,而實際的觀察者,則是一個實作了Observer接口的實體類。如果我們在subscribe時傳入的是一個lambda表達式,之後會被包裝成一個預設的LambdaObserver對象,進行事件消費。

反應式程式設計 RxJava 設計原了解析

五、 包裝的必要

RxJava中提供了豐富的操作符,比如flatMap,concatMap等可以對事件轉換,subscribeOn,observableOn等可以對生産和消費的線程進行控制。這些操作符實際上調用了Observable中的包裝方法對原有的可觀察對象進行包裝,傳回了一個增強了的可觀察對象。

操作符種類繁多,在這就不一一舉例,我們以flatMap為例,分析一下這些操作符是如何工作的。

首先,flatMap操作會傳回一個ObservableFlatMap對象,在建立這個對象時,會将原始的Observable對象作為構造函數的參數傳入。

檢視其核心方法subscribeActual,

反應式程式設計 RxJava 設計原了解析

可以看到這一類對象的subscribeActual方法和上一節中的方法不太一樣,這裡面并沒有去實際的建立觀察關系,而是做了兩件事:

  1. 對觀察者進行增強,将其包裝成為MergeObserver對象,由其對産生的時間進行響應。
  2. 再調用source的subscribe方法,這裡source就是前面構造函數中傳入的Observable對象,由其再進行觀察關系的建立。

    下圖是RxJava中裝飾器模式的相關類圖:所有的包裝類都繼承了AbstractObservableWithUpstream類,該抽象類有一個類型為ObservableSource的成員函數,用來持有被裝飾的對象。

反應式程式設計 RxJava 設計原了解析

Observable是支援鍊式操作的,就和Java 8中的Stream一樣,我們來考慮這樣一行代碼。

反應式程式設計 RxJava 設計原了解析

我們在分析上面這串代碼時,一定會淩亂非常,在看源碼時也會看到前面忘掉後面,但是如果我們對RxJava的包裝流程足夠了解的話,就可以很輕松的對上述代碼進行分析。

反應式程式設計 RxJava 設計原了解析

六、 小結

RxJava的封裝足夠強大,可以讓我們很友善的進行使用和擴充,但這也給我們了解其真實的工作原理帶來了難度,如果我們對整個事件的處理過程處于一知半解的狀态,那我們就無法從容的對服務進行異步編排,在實際開發過程中也難以發現問題的根源。

本文主要分析了RxJava中主要的設計模式,其中有模闆模式、工廠模式、觀察者模式、裝飾器模式,了解了這些設計模式,了解了RxJava中類與類的關系,我們就能夠對整個事件的處理流程了然于胸,分析代碼時也能夠事半功倍。

作者:Yunjie Ma

來源-微信公衆号:vivo網際網路技術

出處:https://mp.weixin.qq.com/s/duO1pAfaKUI2_x_GVvZHMg

繼續閱讀