淺談java響應式編程以及Reactor 3框架
- 2019 年 12 月 8 日
- 筆記
前言
Reactor 3是一個圍繞Reactive Streams規範構建的庫,它在JVM上引入了響應式編程的一個範例。目前Spring5 引入的Webflux就是reactor 3實現的一個響應式web框架。Spring Cloud Gateway是Webflux的一個網關場景實踐。想學好上面這兩項技術必須搞明白響應式編程以及Reactor 3。本篇文章中小胖哥將帶你簡單了解響應式編程和Reactor 3。

為什麼要搞響應式
有這麼一個場景,產品提了一個這麼需求:商品打折,根據商品的原價來計算商品的折扣價。這個需求不是很簡單嘛,按照我們通常的做法,搞一個如下的方法就搞定了。

但是如果我折扣改了呢,這時有人該說重新計算啊。這樣是不是重新走了一次流程呢,我們需要花精力來維護這種流程邏輯。那麼能不能我下游能直接響應上游的變化?就像excel表格計算一樣,下游始終監聽上游,有點風吹草動,結果就會變化。這種潛在的需求就是響應式。響應式編程正是用某種操作符幫助你構建這種關係,而不是執行某種賦值命令。這種思想其實在前端的一些框架中已經風靡很久了。

響應式的特點
基於以上的一個簡單事例。我們可以看出如果是響應式一定要有一個觸發點。就像我們點擊了電腦桌面的QQ圖標一隻企鵝跳啊跳。我們點擊了迅雷圖標有一隻飛鳥在撲騰著翅膀。電腦只維護一個點擊圖標的事件。也就是說響應式編程一定是一個事件觸發機制。並且是以非同步和非阻塞的方式發送和接收的。不是我們平常請求-響應的同步模型。
事件驅動的系統通過push而不是pull來處理,生產者有消息時才推送消息給消費者,而不是通過一種浪費資源方式:讓消費者不斷地輪詢或等待數據。
基於這個機制相對高的吞吐量和實時響應也是響應式的特點。
事件驅動由於Publisher只關心數據源,Consumer只用關心對處理結果的消費。完全是松耦合的。這就給我們很大的操作空間來訂製化我們的邏輯組合,從而使非同步程式碼更易讀和可維護。

Reactor 3 簡介
Reactor 3框架是Pivotal(Spring 母公司)基於Reactive Programming思想實現的。它實現了Reactive Streams(該規範由 Netflix、TypeSafe、Pivotal等公司發起的響應式規範)。其他諸如RxJava 2, Akka Streams, Vert.x和Ratpack也都實現了該規範。
Reactor有一個很重要概念的就是backpressure。 由於生產者消費者處理數據的能力不對等,很容易產生下游消費能力過載的問題。這就需要一個backpressure處理,來告訴上游生產者避免過載。打個比方,一個人負責放水,一個人負責接水,如果放水的速度太快,水桶勢必會濺出來,接水的人會根據情況來告訴放水的人什麼速度最合適,並且在快滿的時候告知放水人關閉開關。
Reactor還添加了運算符的概念,這些運算符被鏈接在一起以描述在每個階段對數據應用的處理。應用運算符返回一個中間Publisher(實際上,它可以被認為是上游運算符的訂閱者和下游的發布者)。數據的最終歸納點在最終Subscriber中(這裡還定義了用戶角度的業務邏輯)。還拿放水舉例,如果我們放水不是為了單純放水而是為了製造肥宅快樂水。這樣就不是一個人接水了,中間加入了原漿流程,下一個接的人接到的是原漿勾兌水,那麼這個人充當了源頭的消費者,也充當了他下游的生產者。他的下游還有加氣兒的。他下游的下游還有罐裝等一系列操作。到最後裝箱整個製程才算告一段落。另外如果下游沒有開工,上游也是不開工的。這樣也符合常理,不可能上游空轉。

上圖揭示了一個最小單元的Reactor流程。其實這些概念更重要的是理解它們。理解了Reactor的特性才能為後面更好的學習java響應式編程打下基礎。後面我們會一起慢慢深入響應式這個話題。