Java反應(yīng)式框架Reactor中的Mono和Flux
1. 前言
最近寫關(guān)于響應(yīng)式編程的東西有點(diǎn)多,很多同學(xué)反映對(duì)Flux
和Mono
這兩個(gè)Reactor中的概念有點(diǎn)懵逼。但是目前Java響應(yīng)式編程中我們對(duì)這兩個(gè)對(duì)象的接觸又最多,諸如Spring WebFlux、RSocket、R2DBC。我開始也對(duì)這兩個(gè)對(duì)象頭疼,所以今天我們就簡單來探討一下它們。
2. 響應(yīng)流的特點(diǎn)
要搞清楚這兩個(gè)概念,必須說一下響應(yīng)流規(guī)范。它是響應(yīng)式編程的基石。他具有以下特點(diǎn):
響應(yīng)流必須是無阻塞的。響應(yīng)流必須是一個(gè)數(shù)據(jù)流。它必須可以異步執(zhí)行。并且它也應(yīng)該能夠處理背壓。
背壓是反應(yīng)流中的一個(gè)重要概念,可以理解為,生產(chǎn)者可以感受到消費(fèi)者反饋的消費(fèi)壓力,并根據(jù)壓力進(jìn)行動(dòng)態(tài)調(diào)整生產(chǎn)速率。形象點(diǎn)可以按照下面理解:
3. Publisher
由于響應(yīng)流的特點(diǎn),我們不能再返回一個(gè)簡單的POJO對(duì)象來表示結(jié)果了。必須返回一個(gè)類似Java中的Future
的概念,在有結(jié)果可用時(shí)通知消費(fèi)者進(jìn)行消費(fèi)響應(yīng)。
Reactive Stream規(guī)范中這種被定義為Publisher<T>
,Publisher<T>
是一個(gè)可以提供0-N個(gè)序列元素的提供者,并根據(jù)其訂閱者Subscriber<? super T>
的需求推送元素。一個(gè)Publisher<T>
可以支持多個(gè)訂閱者,并可以根據(jù)訂閱者的邏輯進(jìn)行推送序列元素。下面這個(gè)Excel計(jì)算就能說明一些Publisher<T>
的特點(diǎn)。
A1-A9就可以看做Publisher<T>
及其提供的元素序列。A10-A13分別是求和函數(shù)SUM(A1:A9)
、平均函數(shù)AVERAGE(A1:A9)
、最大值函數(shù)MAX(A1:A9)
、最小值函數(shù)MIN(A1:A9)
,可以看作訂閱者Subscriber
。假如說我們沒有A10-A13,那么A1-A9就沒有實(shí)際意義,它們并不產(chǎn)生計(jì)算。這也是響應(yīng)式的一個(gè)重要特點(diǎn):當(dāng)沒有訂閱時(shí)發(fā)布者什么也不做。
而Flux
和Mono
都是Publisher<T>
在Reactor 3實(shí)現(xiàn)。Publisher<T>
提供了subscribe
方法,允許消費(fèi)者在有結(jié)果可用時(shí)進(jìn)行消費(fèi)。如果沒有消費(fèi)者Publisher<T>
不會(huì)做任何事情,他根據(jù)消費(fèi)情況進(jìn)行響應(yīng)。 Publisher<T>
可能返回零或者多個(gè),甚至可能是無限的,為了更加清晰表示期待的結(jié)果就引入了兩個(gè)實(shí)現(xiàn)模型Mono
和Flux
。
4. Flux
Flux
是一個(gè)發(fā)出(emit)0-N
個(gè)元素組成的異步序列的Publisher<T>
,可以被onComplete
信號(hào)或者onError
信號(hào)所終止。在響應(yīng)流規(guī)范中存在三種給下游消費(fèi)者調(diào)用的方法 onNext
, onComplete
, 和onError
。下面這張圖表示了Flux的抽象模型:
以上的的講解對(duì)于初次接觸反應(yīng)式編程的依然是難以理解的,所以這里有一個(gè)循序漸進(jìn)的理解過程。
有些類比并不是很妥當(dāng),但是對(duì)于你循序漸進(jìn)的理解這些新概念還是有幫助的。
傳統(tǒng)數(shù)據(jù)處理
我們在平常是這么寫的:
public List<ClientUser> allUsers() { return Arrays.asList(new ClientUser("felord.cn", "reactive"), new ClientUser("Felordcn", "Reactor")); }
我們通過迭代返回值List
來get
這些元素進(jìn)行再處理(消費(fèi)),這種方式有點(diǎn)類似廚師做了很多菜,吃不吃在于食客。需要食客主動(dòng)去來吃就行了(pull的方式),至于喜歡吃什么不喜歡吃什么自己隨意,怎么吃也自己隨意。
流式數(shù)據(jù)處理
在Java 8中我們可以改寫為流的表示:
public Stream<ClientUser> allUsers() { return Stream.of(new ClientUser("felord.cn", "reactive"), new ClientUser("Felordcn", "Reactor")); }
依然是廚師做了很多菜,但是這種就更加高級(jí)了一些,提供了菜品的搭配方式(不包含具體細(xì)節(jié)),食客可以按照說明根據(jù)自己的習(xí)慣搭配著去吃,一但開始概不退換,吃完為止,過期不候。
反應(yīng)式數(shù)據(jù)處理
在Reactor中我們又可以改寫為Flux
表示:
public Flux<ClientUser> allUsers(){ return Flux.just(new ClientUser("felord.cn", "reactive"), new ClientUser("Felordcn", "Reactor")); }
這時(shí)候食客只需要訂餐就行了,做好了自然就呈上來,而且可以隨時(shí)根據(jù)食客的飯量進(jìn)行調(diào)整。如果沒有食客訂餐那么廚師就什么都不用做。當(dāng)然不止有這么點(diǎn)特性,不過對(duì)于方便我們理解來說這就夠了。
5. Mono
Mono
是一個(gè)發(fā)出(emit)0-1
個(gè)元素的Publisher<T>
,可以被onComplete
信號(hào)或者onError
信號(hào)所終止。
這里就不翻譯了,整體和Flux
差不多,只不過這里只會(huì)發(fā)出0-1個(gè)元素。也就是說不是有就是沒有。象Flux
一樣,我們來看看Mono
的演化過程以幫助理解。
傳統(tǒng)數(shù)據(jù)處理
public ClientUser currentUser () { return isAuthenticated ? new ClientUser("felord.cn", "reactive") : null; }
直接返回符合條件的對(duì)象或者null
。
Optional的處理方式
public Optional<ClientUser> currentUser () { return isAuthenticated ? Optional.of(new ClientUser("felord.cn", "reactive")) : Optional.empty(); }
這個(gè)Optional
我覺得就有反應(yīng)式的那種味兒了,當(dāng)然它并不是反應(yīng)式。當(dāng)我們不從返回值Optional
取其中具體的對(duì)象時(shí),我們不清楚里面到底有沒有,但是Optional
是一定客觀存在的,不會(huì)出現(xiàn)NPE問題。
反應(yīng)式數(shù)據(jù)處理
public Mono<ClientUser> currentUser () { return isAuthenticated ? Mono.just(new ClientUser("felord.cn", "reactive")) : Mono.empty(); }
和Optional
有點(diǎn)類似的機(jī)制,當(dāng)然Mono
不是為了解決NPE問題的,它是為了處理響應(yīng)流中單個(gè)值(也可能是Void
)而存在的。
6. 總結(jié)
Flux
和Mono
是Java反應(yīng)式中的重要概念,但是很多同學(xué)包括我在開始都難以理解它們。這其實(shí)是規(guī)定了兩種流式范式,這種范式讓數(shù)據(jù)具有一些新的特性,比如基于發(fā)布訂閱的事件驅(qū)動(dòng),異步流、背壓等等。另外數(shù)據(jù)是推送(Push)給消費(fèi)者的以區(qū)別于平時(shí)我們的拉(Pull)模式。同時(shí)我們可以像Stream Api一樣使用類似map
、flatmap
等操作符(operator)來操作它們。對(duì)Flux
和Mono
這兩個(gè)概念需要花一些時(shí)間去理解它們,不能操之過急。
到此這篇關(guān)于Java反應(yīng)式框架Reactor中的Mono和Flux的文章就介紹到這了,更多相關(guān)Java框架 Reactor中的Mono和Flux內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringCloud?hystrix斷路器與局部降級(jí)全面介紹
什么是服務(wù)降級(jí)?當(dāng)服務(wù)器壓力劇增的情況下,根據(jù)實(shí)際業(yè)務(wù)情況及流量,對(duì)一些服務(wù)和頁面有策略的不處理或換種簡單的方式處理,從而釋放服務(wù)器資源以保證核心交易正常運(yùn)作或高效運(yùn)作2022-10-10SpringBoot整合Minio實(shí)現(xiàn)上傳文件的完整步驟記錄
MinIO是一個(gè)基于Apache License v2.0開源協(xié)議的對(duì)象存儲(chǔ)服務(wù),它兼容亞馬遜S3云存儲(chǔ)服務(wù)接口,非常適合于存儲(chǔ)大容量非結(jié)構(gòu)化的數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合Minio實(shí)現(xiàn)上傳文件的完整步驟,需要的朋友可以參考下2022-05-05關(guān)于通過java調(diào)用datax,返回任務(wù)執(zhí)行的方法
今天小編就為大家分享一篇關(guān)于通過java調(diào)用datax,返回任務(wù)執(zhí)行的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-08-08SpringBoot集成gRPC微服務(wù)工程搭建實(shí)踐的方法
這篇文章主要介紹了SpringBoot集成gRPC微服務(wù)工程搭建實(shí)踐的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01Java實(shí)現(xiàn)簡單的郵件發(fā)送功能
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡單的郵件發(fā)送功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07