應用響應式Web開發(fā)組件-響應式編程和Spring Boot
當下,對于具有廣大用戶群體的新型互聯(lián)網(wǎng)應用而言,它們基本都需要 考慮如何高效應對用戶流量、如何確保系統(tǒng)彈性等核心技術主題。在理論和 實踐的結合下,響應式編程是一種新型的編程模型,是確保系統(tǒng)彈性的一款 強有力的武器。在響應式編程領域,存在一套完整的響應式流規(guī)范以及實現(xiàn) 這一規(guī)范的開發(fā)工具。在現(xiàn)實中,開發(fā)人員通常不會直接使用這些偏底層的 開發(fā)工具來開發(fā)應用程序,而是借助于特定的開發(fā)框架。而我們?nèi)粘i_發(fā)中 每天都在使用的Spring就是這樣一個支持響應式編程的開發(fā)框架。
在2017年,Spring發(fā)布了新版本Spring 5,這是自Spring 4發(fā)布以來將 近4年的時間中所發(fā)布的第一個全新版本。Spring 5引入了很多核心功能,重 要的是它全面擁抱了響應式編程的設計思想和實踐。
Spring 5的響應式編程模型以Project Reactor庫為基礎,而后者則實現(xiàn) 了響應式流規(guī)范。事實上,Spring Boot從2.x版本開始全面依賴Spring 5。
Spring Boot為我們提供了一系列響應式編程組件,而本章將重點關注如何使 用Spring Boot框架來開發(fā)響應式Web服務。
響應式編程和Spring Boot
響應式編程是一種新的編程技術,其目的是構建響應式系統(tǒng)。對于響應 式系統(tǒng)而言,任何時候都需要確保其具備即時響應性,這是大多數(shù)日常業(yè)務 場景所需要的,但卻是一項非常復雜而有挑戰(zhàn)性的任務,需要對相關技術有 深入的了解。本節(jié)將討論這些技術。
響應式流規(guī)范和實現(xiàn)框架
對于響應式編程而言,首先要明確的概念是數(shù)據(jù)流(Data Stream)。簡 單來講,所謂的流就是由生產(chǎn)者生產(chǎn)并由一個或多個消費者消費的元素序 列。而一旦有了數(shù)據(jù)流,那么就勢必面臨流量控制問題。流量控制是討論數(shù) 據(jù)流的核心話題。而針對如何控制流量,業(yè)界存在一個響應式流規(guī)范,以及 一批實現(xiàn)了該規(guī)范的開發(fā)工具。
1. 響應式流規(guī)范
Java API版本的響應式流只包含四個接口,即Publisher<T>、 Subscriber<T>、Subscription和Processor<T,R>。
發(fā)布者(Publisher)是潛在的包含無限數(shù)量的有序元素的生產(chǎn)者,它根 據(jù)收到的請求向當前訂閱者發(fā)送元素。Publisher<T>接口定義如代碼清單5-1 所示。
代碼清單5-1 Publisher<T>接口定義代碼
public interface Publisher<T> {
public void subscribe(Subscriber<? super T> s);
}
訂閱者(Subscriber)從發(fā)布者那里訂閱并接收元素。發(fā)布者向訂閱者 發(fā)送訂閱令牌(Subscription Token)。通過訂閱令牌,訂閱者就可以向發(fā) 布者請求多個元素。當元素準備就緒時,發(fā)布者就會向訂閱者發(fā)送合適數(shù)量 的元素。然后訂閱者可以請求更多的元素,發(fā)布者也可能有多個來自訂閱者 的待處理請求。Subscriber <T>接口定義如代碼清單5-2所示。

當執(zhí)行發(fā)布者的subscribe()方法時,發(fā)布者會回調(diào)訂閱者的 onSubscribe()方法。在這個方法中,通常訂閱者會借助傳入的Subscription 對象向發(fā)布者請求n個數(shù)據(jù)。然后發(fā)布者通過不斷調(diào)用訂閱者的onNext()方法 向訂閱者發(fā)出最多n個數(shù)據(jù)。如果數(shù)據(jù)全部發(fā)完,則會調(diào)用onComplete()方法 告知訂閱者流已經(jīng)發(fā)完;如果有錯誤發(fā)生,則通過onError()方法發(fā)出錯誤提 示消息,這時同樣也會終止數(shù)據(jù)流。
訂閱(Subscription)表示訂閱者訂閱的一個令牌。當訂閱請求成功 時,發(fā)布者將其傳遞給訂閱者。訂閱者使用訂閱令牌與發(fā)布者進行交互,例 如請求更多的元素或取消訂閱。Subscription接口定義如代碼清單5-3所示。

當發(fā)布者調(diào)用subscribe()方法注冊訂閱者時,會通過訂閱者的回調(diào)方法 onSubscribe()傳入Subscription對象,之后訂閱者就可以使用這個 Subscription對象的request()方法向發(fā)布者請求數(shù)據(jù)。
處理器(Processor)充當訂閱者和發(fā)布者之間的轉(zhuǎn)換器 (Transformer)。Processor<T,R>訂閱類型T的數(shù)據(jù)元素,接收并轉(zhuǎn)換為類 型R的數(shù)據(jù),發(fā)布該數(shù)據(jù)。Processor接口同時繼承了Publisher和Subscriber 接口,其定義如代碼清單5-4所示。

上述四個接口是各個響應式開發(fā)庫之間互相實現(xiàn)兼容的橋梁,響應式流 規(guī)范也僅僅聚焦于此,而對諸如轉(zhuǎn)換、合并、分組等的操作一概未做要求, 因此是一個非常抽象且精簡的接口規(guī)范。
作為總結,我們可以把響應式流規(guī)范核心接口的交互方式梳理成圖5-1。

可以看到,圖5-1中所示的交互方式一共包含如下7個步驟。
1)當發(fā)布者使用subscribe()方法實現(xiàn)對該發(fā)布者的訂閱時,首先會創(chuàng) 建一個具有相應邏輯的Subscription對象,這個Subscription對象定義了如 何處理請求,以及如何發(fā)出數(shù)據(jù)。
2)然后發(fā)布者將這個Subscription通過訂閱者的onSubscribe()方法傳 給訂閱者。
3)在訂閱者的onSubscribe()方法中,需要通過Subscription的request ()方法發(fā)起第一次請求。
4)Subscription收到請求,就可以通過回調(diào)訂閱者的onNext()方法發(fā)出 元素,有多少發(fā)多少,但不能超過請求的個數(shù)。
5)訂閱者在onNext()方法中通常定義對元素的處理邏輯,處理完成之 后,可以繼續(xù)發(fā)起請求。
6)發(fā)布者根據(jù)需要繼續(xù)滿足訂閱者的請求。
7)如果發(fā)布者的元素序列正常結束,就通過訂閱者的onComplete()方法 予以告知。如果序列發(fā)送過程中有錯誤,則通過訂閱者的onError()方法予以 告知并傳遞錯誤提示。這兩種情況都會導致序列終止,訂閱過程結束。
2. Project Reactor
Spring 5引入了響應式編程機制,并默認集成了Project Reactor(下文 簡稱為Reactor)作為該機制的實現(xiàn)框架。Reactor誕生較晚,可以認為它是 第二代響應式開發(fā)框架。所以它是一款完全基于響應式流規(guī)范設計和實現(xiàn)的 工具庫,在使用上直觀易懂。
在Reactor框架中,數(shù)據(jù)流的表現(xiàn)形式如圖5-2所示。

圖5-2中的數(shù)據(jù)流模型從語義上可以用如下公式表示:
onNext x 0..N [onError | onComplete]
上述公式包含了如下三種不同類型的方法調(diào)用,分別處理不同場景下的 消息通知。
onNext():正常包含元素的消息通知。
onComplete():序列結束的消息通知。
onError():序列出錯的消息通知,可以沒有。
按照響應式流規(guī)范,當這些消息通知產(chǎn)生時,訂閱者中對應的 onNext()、onComplete()和onError()這三個方法將被調(diào)用。如果序列沒有出 錯,則onError()方法不會被調(diào)用;而如果不調(diào)用onComplete()方法,我們就 會得到一個無限異步序列。通常,無限異步序列應該只用于測試等特殊場 景。
針對數(shù)據(jù)流,Reactor提供了兩個核心組件,即Flux和Mono。其中Flux代 表包含0到n個元素的異步序列,而Mono則表示包含0個或1個元素的異步序 列。
創(chuàng)建Flux的方式非常多,這些方式可以分成兩大類,一類是充分利用 Flux的靜態(tài)方法,另一類則是動態(tài)創(chuàng)建Flux。這里的靜態(tài)方法常見的包括 just()、fromArray()、fromIterable()、fromStream()、empty()、 error()、never()、range()、interval()等,而動態(tài)方法則包括generate() 和create()。創(chuàng)建Mono的方式也類似。 另外,和其他主流的響應式編程框架一樣,Reactor框架的設計目標也是 為了簡化響應式流的使用方法。為此,Reactor框架為我們提供了大量操作符 用于操作Flux和Mono對象。常見的包括用于數(shù)據(jù)轉(zhuǎn)換的flatMap、用于數(shù)據(jù)過 濾的filter、用于操作組合的zipWith、用于條件控制的defaultIfEmpty,以 及subscribe和log等工具操作符。
由于本章的重點是介紹Spring WebFlux,而Project Reactor是WebFlux 的底層框架,我們一般不會直接使用該框架開發(fā)Web應用程序。因此,針對 Flux和Mono的創(chuàng)建方法以及各種操作符,我們不打算做全面而細致的介紹, 讀者可參考Reactor框架的官方文檔以及筆者翻譯的《Spring響應式編程》一 書做進一步了解。
本文就是愿天堂沒有BUG給大家分享的內(nèi)容,大家有收獲的話可以分享下,想學習更多的話可以到微信公眾號里找我,我等你哦。
