日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

阿里专家杜万:Java响应式编程,一文全面解读

發布時間:2024/8/23 java 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 阿里专家杜万:Java响应式编程,一文全面解读 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本篇文章來自于2018年12月22日舉辦的《阿里云棲開發者沙龍—Java技術專場》,杜萬專家是該專場第四位演講的嘉賓,本篇文章是根據杜萬專家在《阿里云棲開發者沙龍—Java技術專場》的演講視頻以及PPT整理而成。


摘要:響應式宣言如何解讀,Java中如何進行響應式編程,Reactor Streams又該如何使用?熱衷于整合框架與開發工具的阿里云技術專家杜萬,為大家全面解讀響應式編程,分享Spring Webflux的實踐。從響應式理解,到Reactor項目示例,再到Spring Webflux框架解讀,本文帶你進入Java響應式編程。

演講嘉賓簡介:
杜萬(倚賢),阿里云技術專家,全棧工程師,從事了12年 Java 語言為主的軟件開發工作,熱衷于整合框架與開發工具,Linux擁躉,問題終結者。合作翻譯《Elixir 程序設計》。目前負責阿里云函數計算的工具鏈開發,正在實踐 WebFlux 和 Reactor 開發新的 Web 應用。

本次直播視頻精彩回顧,戳這里!https://yq.aliyun.com/live/721
PPT下載地址:https://yq.aliyun.com/download/3187
以下內容根據演講嘉賓視頻分享以及PPT整理而成。

本文圍繞以下三部分進行介紹:
1.Reactive
2.Project Reactor
3.Spring Webflux

一.Reactive
1.Reactive Manifesto
下圖是Reactive Manifesto官方網站上的介紹,這篇文章非常短但也非常精悍,非常值得大家去認真閱讀。


響應式宣言是一份構建現代云擴展架構的處方。這個框架主要使用消息驅動的方法來構建系統,在形式上可以達到彈性和韌性,最后可以產生響應性的價值。所謂彈性和韌性,通俗來說就像是橡皮筋,彈性是指橡皮筋可以拉長,而韌性指在拉長后可以縮回原樣。這里為大家一一解讀其中的關鍵詞:
1)響應性:快速/一致的響應時間。假設在有500個并發操作時,響應時間為1s,那么并發操作增長至5萬時,響應時間也應控制在1s左右。快速一致的響應時間才能給予用戶信心,是系統設計的追求。
2)韌性:復制/遏制/隔絕/委托。當某個模塊出現問題時,需要將這個問題控制在一定范圍內,這便需要使用隔絕的技術,避免連鎖性問題的發生。或是將出現故障部分的任務委托給其他模塊。韌性主要是系統對錯誤的容忍。
3)彈性:無競爭點或中心瓶頸/分片/擴展。如果沒有狀態的話,就進行水平擴展,如果存在狀態,就使用分片技術,將數據分至不同的機器上。
4)消息驅動:異步/松耦合/隔絕/地址透明/錯誤作為消息/背壓/無阻塞。消息驅動是實現上述三項的技術支撐。其中,地址透明有很多方法。例如DNS提供的一串人類能讀懂的地址,而不是IP,這是一種不依賴于實現,而依賴于聲明的設計。再例如k8s每個service后會有多個Pod,依賴一個虛擬的服務而不是某一個真實的實例,從何實現調用1 個或調用n個服務實例對于對調用方無感知,這是為分片或擴展做了準備。錯誤作為消息,這在Java中是不太常見的,Java中通常將錯誤直接作為異常拋出,而在響應式中,錯誤也是一種消息,和普通消息地位一致,這和JavaScript中的Promise類似。背壓是指當上游向下游推送數據時,可能下游承受能力不足導致問題,一個經典的比喻是就像用消防水龍頭解渴。因此下游需要向上游聲明每次只能接受大約多少量的數據,當接受完畢再次向上游申請數據傳輸。這便轉換成是下游向上游申請數據,而不是上游向下游推送數據。無阻塞是通過no-blocking IO提供更高的多線程切換效率。


2.Reactive Programming
響應式編程是一種聲明式編程范型。下圖中左側顯示了一個命令式編程,相信大家都比較熟悉。先聲明兩個變量,然后進行賦值,讓兩個變量相加,得到相加的結果。但接著當修改了最早聲明的兩個變量的值后,sum的值不會因此產生變化。而在Java 9 Flow中,按相同的思路實現上述處理流程,當初始變量的值變化,最后結果的值也同步發生變化,這就是響應式編程。這相當于聲明了一個公式,輸出值會隨著輸入值而同步變化。


響應式編程也是一種非阻塞的異步編程。下圖是用reactor.ipc.netty實現的TCP通信。常見的server中會用循環發數據后,在循環外取出,但在下圖的實現中沒有,因為這不是使用阻塞模型實現,是基于非阻塞的異步編程實現。


響應式編程是一種數據流編程,關注于數據流而不是控制流。下圖中,首先當頁面出現點擊操作時產生一個click stream,然后頁面會將250ms內的clickStream緩存,如此實現了一個歸組過程。然后再進行map操作,得到每個list的長度,篩選出長度大于2的,這便可以得出多次點擊操作的流。這種方法應用非常廣泛,例如可以篩選出雙擊操作。由此可見,這種編程方式是一種數據流編程,而不是if else的控制流編程。


之前有提及消息驅動,那么消息驅動(Message-driven)和事件驅動(Event-driven)有什么區別呢。
1)消息驅動有確定的目標,一定會有消息的接受者,而事件驅動是一件事情希望被觀察到,觀察者是誰無關緊要。消息驅動系統關注消息的接受者,事件驅動系統關注事件源。
2)在一個使用響應式編程實現的響應式系統中,消息擅長于通訊,事件擅長于反應事實。
3.Reactive Streams
Reactive Streams提供了一套非阻塞背壓的異步流處理標準,主要應用在JVM、JavaScript和網絡協議工作中。通俗來說,它定義了一套響應式編程的標準。在Java中,有4個Reactive Streams API,如下圖所示:


這個API中定義了Publisher,即事件的發生源,它只有一個subscribe方法。其中的Subscriber就是訂閱消息的對象。


作為訂閱者,有四個方法。onSubscribe會在每次接收消息時調用,得到的數據都會經過onNext方法。onError方法會在出現問題時調用,Throwable即是出現的錯誤消息。在結束時調用onComplete方法。


Subscription接口用來描述每個訂閱的消息。request方法用來向上游索要指定個數的消息,cancel方法用于取消上游的數據推送,不再接受消息。


Processor接口繼承了Subscriber和Publisher,它既是消息的發生者也是消息的訂閱者。這是發生者和訂閱者間的過渡橋梁,負責一些中間轉換的處理。
Reactor Library從開始到現在已經歷經多代。第0代就是java包Observable 接口,也就是觀察者模式。具體的發展見下圖:


第四代雖然仍然是RxJava2,但是相比第三代的RxJava2,其中的小版本有了不一樣的改進,出現了新特性。
Reactor Library主要有兩點特性。一是基于回調(callback-based),在事件源附加回調函數,并在事件通過數據流鏈時被調用;二是聲明式編程(Declarative),很多函數處理業務類似,例如map/filter/fold等,這些操作被類庫固化后便可以使用聲明式方法,以在程序中快速便捷使用。在生產者、訂閱者都定義后,聲明式方法便可以用來實現中間處理者。

二.Project Reactor
Project Reactor,實現了完全非阻塞,并且基于網絡HTTP/TCP/UDP等的背壓,即數據傳輸上游為網絡層協議時,通過遠程調用也可以實現背壓。同時,它還實現了Reactive Streams API和Reactive Extensions,以及支持Java 8 functional API/Completable Future/Stream /Duration等各新特性。下圖所示為Reactor的一個示例:


首先定義了一個words的數組,然后使用flatMap做映射,再將每個詞和s做連接,得出的結果和另一個等長的序列進行一個zipWith操作,最后打印結果。這和Java 8 Stream非常類似,但仍存在一些區別:
1)Stream是pull-based,下游從上游拉數據的過程,它會有中間操作例如map和reduce,和終止操作例如collect等,只有在終止操作時才會真正的拉取數據。Reactive是push-based,可以先將整個處理數據量構造完成,然后向其中填充數據,在出口處可以取出轉換結果。
2)Stream只能使用一次,因為它是pull-based操作,拉取一次之后源頭不能更改。但Reactive可以使用多次,因為push-based操作像是一個數據加工廠,只要填充數據就可以一直產出。
3)Stream#parallel()使用fork-join并發,就是將每一個大任務一直拆分至指定大小顆粒的小任務,每個小任務可以在不同的線程中執行,這種多線程模型符合了它的多核特性。Reactive使用Event loop,用一個單線程不停的做循環,每個循環處理有限的數據直至處理完成。
在上例中,大家可以看到很多Reactive的操作符,例如flatMap/concatWith/zipWith等,這樣的操作符有300多個,這可能是學習這個框架最大的壓力。如何理解如此繁多的操作符,可能一個歸類會有所幫助:


1)新序列創建,例如創建數組類序列等;
2)現有序列轉換,將其轉換為新的序列,例如常見的map操作;
3)從現有的序列取出某些元素;
4)序列過濾;
5)序列異常處理。
6)與時間相關的操作,例如某個序列是由時間觸發器定期發起事件;
7)序列分割;
8)序列拉至同步世界,不是所有的框架都支持異步,再需要和同步操作進行交互時就需要這種處理。
上述300+操作符都有如下所示的彈珠圖(Marble Diagrams),用表意的方式解釋其作用。例如下圖的操作符是指,隨著時間推移,逐個產生了6個元素的序列,黑色豎線表示新元素產生終止。在這個操作符的作用下,下方只取了前三個元素,到第四個元素就不取了。這些彈珠圖大家可以自行了解。


三.Spring Webflux
1.Spring Webflux框架
Spring Boot 2.0相較之前的版本,在基于Spring Framework 5的構建添加了新模塊Webflux,將默認的web服務器改為Netty,支持Reactive應用,并且Webflux默認運行在Netty上。而Spring Framework 5也有了一些變化。Java版本最低依賴Java 8,支持Java 9和Java 10,提供許多支持Reactive的基礎設施,提供面向Netty等運行時環境的適配器,新增Webflux模塊(集成的是Reactor 3.x)。下圖所示為Webflux的框架:


左側是通常使用的框架,通過Servlet API的規范和Container進行交互,上一層是Spring-Webmvc,再上一層則是經常使用的一些注解。右側為對應的Webflux層級,只要是支持NIO的Container,例如Tomcat,Jetty,Netty或Undertow都可以實現。在協議層的是HTTP/Reactive Streams。再上一層是Spring-Webflux,為了保持兼容性,它支持這些常用的注解,同時也有一套新的語法規則Router Functions。下圖顯示了一個調用的實例:


在Client端,首先創建一個WebClient,調用其get方法,寫入URL,接收格式為APPLICATION_STREAM_JSON的數據,retrieve獲得數據,取得數據后用bodyToFlux將數據轉換為Car類型的對象,在doOnNext中打印構造好的Car對象,block方法意思是直到回調函數被執行才可以結束。在Server端,在指定的path中進行get操作,produces和以前不同,這里是application/stream+json,然后返回Flux范型的Car對象。傳統意義上,如果數據中有一萬條數據,那么便直接返回一萬條數據,但在這個示例返回的Flux范型中,是不包含數據的,但在數據庫也支持Reactive的情況下,request可以一直往下傳遞,響應式的批量返回。傳統方式這樣的查詢很有可能是一個全表遍歷,這會需要較多資源和時間,甚至影響其他任務的執行。而響應式的方法除了可以避免這種情況,還可以讓用戶在第一時間看到數據而不是等待數據采集完畢,這在架構體驗的完整性上有了很大的提升。application/stream+json也是可以讓前端識別出,這些數據是分批響應式傳遞,而不會等待傳完才顯示。
現在的Java web應用可以使用Servlet棧或Reactive棧。Servlet棧已經有很久的使用歷史了,而現在又增加了更有優勢的Reactive棧,大家可以嘗試實現更好的用戶體驗。


2.Reactive編程模型
下圖中是Spring實現的一個向后兼容模型,可以使用annotation來標注Container。這是一個非常清晰、支持非常細節化的模型,也非常利于同事間的交流溝通。


下圖是一個Functional編程模型,通過寫函數的方式構造。例如下圖中傳入一個Request,返回Response,通過函數的方法重點關注輸入輸出,不需要區分狀態。然后將這些函數注冊至Route。這個模型和Node.js非常接近,也利于使用。


3.Spring Data框架
Spring Data框架支持多種數據庫,如下圖所示,最常用的是JPA和JDBC。在實踐中,不同的語言訪問不同的數據庫時,訪問接口是不一樣的,這對編程人員來說是個很大的工作量。
Spring Data便是做了另一層抽象,使你無論使用哪種數據庫,都可以使用同一個接口。具體特性這里不做詳談。


下圖展示了一個Spring Data的使用示例。只需要寫一個方法簽名,然后注解為Query,這個方法不需要實現,因為框架后臺已經采用一些技術,直接根據findByFirstnameAndLastname就可以查詢到。這種一致的調用方式無疑提供了巨大的方便。


現在Reactive對Spring Data的支持還是不完整的,只支持了MongoDB/Redis/Cassandra和Couchbase,對JPA/LDAP/Elasticsearch/Neo4j/Solr等還不兼容。但也不是不能使用,例如對JDBC數據庫,將其轉為同步即可使用,重點在于findAll和async兩個函數,這里不再展開詳述,具體代碼如下圖所示:


Reactive不支持JDBC最根本的原因是,JDBC不是non-blocking設計。但是現在JavaOne已經在2016年9月宣布了Non-blocking JDBC API的草案,雖然還未得到Java 10的支持,但可見這已經成為一種趨勢。

四.總結
Spring MVC框架是一個命令式邏輯,方便編寫和調試。Spring WebFlux也具有眾多優勢,但調試卻不太容易,因為它經常需要切換線程執行,出現錯誤的棧可能已經銷毀。當然這也是現今Java的編譯工具對WebFlux不太友好,相信以后會改善。下圖中列出了Spring MVC和Spring WebFlux各自的特性及交叉的部分。最后也附上一些參考資料。

?

?


原文鏈接
本文為云棲社區原創內容,未經允許不得轉載。

總結

以上是生活随笔為你收集整理的阿里专家杜万:Java响应式编程,一文全面解读的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。