1. 程式人生 > >精講響應式webclient第1篇-響應式非阻塞IO與基礎用法

精講響應式webclient第1篇-響應式非阻塞IO與基礎用法

筆者在之前已經寫了一系列的關於RestTemplate的文章,如下: * [精講RestTemplate第1篇-在Spring或非Spring環境下如何使用](http://www.zimug.com/java/spring/%e7%b2%be%e8%ae%b2resttemplate%e7%ac%ac1%e7%af%87-%e5%9c%a8spring%e6%88%96%e9%9d%9espring%e7%8e%af%e5%a2%83%e4%b8%8b%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8/.html) * [精講RestTemplate第2篇-多種底層HTTP客戶端類庫的切換](http://www.zimug.com/java/spring/%e7%b2%be%e8%ae%b2resttemplate%e7%ac%ac2%e7%af%87-%e5%a4%9a%e7%a7%8d%e5%ba%95%e5%b1%82http%e5%ae%a2%e6%88%b7%e7%ab%af%e7%b1%bb%e5%ba%93%e7%9a%84%e5%88%87%e6%8d%a2/.html) * [精講RestTemplate第3篇-GET請求使用方法詳解](http://www.zimug.com/java/spring/%e7%b2%be%e8%ae%b2resttemplate%e7%ac%ac3%e7%af%87-get%e8%af%b7%e6%b1%82%e4%bd%bf%e7%94%a8%e6%96%b9%e6%b3%95%e8%af%a6%e8%a7%a3/.html) * [精講RestTemplate第4篇-POST請求方法使用詳解](http://www.zimug.com/java/spring/%e7%b2%be%e8%ae%b2resttemplate%e7%ac%ac4%e7%af%87-post%e8%af%b7%e6%b1%82%e6%96%b9%e6%b3%95%e4%bd%bf%e7%94%a8%e8%af%a6%e8%a7%a3/.html) * [精講RestTemplate第5篇-DELETE、PUT等請求方法使用詳解](http://www.zimug.com/java/%e7%b2%be%e8%ae%b2resttemplate%e7%ac%ac4%e7%af%87-delete%e3%80%81put%e7%ad%89%e8%af%b7%e6%b1%82%e6%96%b9%e6%b3%95%e4%bd%bf%e7%94%a8%e8%af%a6%e8%a7%a3/.html) * [精講RestTemplate第6篇-檔案上傳下載與大檔案流式下載](http://www.zimug.com/java/spring/%e7%b2%be%e8%ae%b2resttemplate%e7%ac%ac6%e7%af%87-%e6%96%87%e4%bb%b6%e4%b8%8a%e4%bc%a0%e4%b8%8b%e8%bd%bd%e4%b8%8e%e5%a4%a7%e6%96%87%e4%bb%b6%e6%b5%81%e5%bc%8f%e4%b8%8b%e8%bd%bd/.html) * [精講RestTemplate第7篇-自定義請求失敗異常處理](http://www.zimug.com/java/spring/%e7%b2%be%e8%ae%b2resttemplate%e7%ac%ac7%e7%af%87-%e8%87%aa%e5%ae%9a%e4%b9%89%e8%af%b7%e6%b1%82%e5%a4%b1%e8%b4%a5%e5%bc%82%e5%b8%b8%e5%a4%84%e7%90%86/.html) * [精講RestTemplate第8篇-請求失敗自動重試機制](http://www.zimug.com/java/spring/%e7%b2%be%e8%ae%b2resttemplate%e7%ac%ac8%e7%af%87-%e8%af%b7%e6%b1%82%e5%a4%b1%e8%b4%a5%e8%87%aa%e5%8a%a8%e9%87%8d%e8%af%95%e6%9c%ba%e5%88%b6/.html) * [精講RestTemplate第9篇-如何通過HTTP Basic Auth認證](http://www.zimug.com/java/spring/%e7%b2%be%e8%ae%b2resttemplate%e7%ac%ac9%e7%af%87-%e5%a6%82%e4%bd%95%e9%80%9a%e8%bf%87http-basic-auth%e8%ae%a4%e8%af%81/.html) * [精講RestTemplate第10篇-使用代理作為跳板傳送請求](http://www.zimug.com/java/spring/%e7%b2%be%e8%ae%b2resttemplate%e7%ac%ac10%e7%af%87-%e4%bd%bf%e7%94%a8%e4%bb%a3%e7%90%86%e4%bd%9c%e4%b8%ba%e8%b7%b3%e6%9d%bf%e5%8f%91%e9%80%81%e8%af%b7%e6%b1%82/.html) `RestTemplate`作為spring-web專案的一部分,在Spring 3.0版本開始被引入。根據Spring官方文件及原始碼中的介紹,RestTemplate在將來的版本中它可能會被棄用, 作為替代,Spring官方已在Spring 5中引入了WebClient作為非阻塞式Reactive HTTP客戶端。 ![RestTemplate在將來的版本中它可能會被棄用](https://img2020.cnblogs.com/other/1815316/202008/1815316-20200820075830997-1910618140.png) ## 一、什麼是響應式非阻塞IO 在開始為大家介紹webClient之前有必要為大家介紹一下響應式非阻塞IO與傳統IO之前的區別。我們先留下一個問題:**webClient傳送與接收單個HTTP請求比RestTemplate更快麼?答案是否定的。** 看到這裡有的同學已經蒙了,既然webClient沒有更快,那官方為什麼還推薦使用它?聽我往下講。 ### 1.1.傳統阻塞式IO模型 筆者用相對通俗的話為大家說明一下阻塞IO與非阻塞IO之間的區別。我們以軟體開發團隊的工作方式來做一個比喻。作為軟體開發人員,我們肯定知道軟體開發的基本流程: * 專案立項與可行性研究 * 需求分析與設計 * 程式碼開發 * 迭代測試 * 上線及配置管理、運維 ![](https://img2020.cnblogs.com/other/1815316/202008/1815316-20200820075831267-976890432.png) 在以Spring MVC或者struct為代表的框架都是基於sevlet的,其底層IO模型是阻塞IO模型。這種模型就好像你是公司的一個開發人員,上面的所有的5項工作全都由你一個人完成。如果公司有10個人,最多就只能**同時進行**10個需求。客戶需求增多了也沒有辦法,只能讓他們等著。如下圖:一個請求佔用一個執行緒,當執行緒池內的執行緒都被佔用後新來的請求就只能等待。 ### 1.2.響應式IO模型 spring 社群為了解決Spring MVC的阻塞模型在高併發場景下的效能瓶頸的問題,推出了Spring WebFlux,WebFlux底層實現是久經考驗的netty非阻塞IO通訊框架。該框架的請求處理與執行緒互動關係圖如下: ![](https://img2020.cnblogs.com/other/1815316/202008/1815316-20200820075831890-443121737.png) boosGroup用於Accetpt連線建立事件並分發請求, workerGroup用於處理I/O讀寫事件。netty我就不細說了,還是用通俗的方式給大家講一下:如果通俗的將上圖中的各個任務池、執行緒池的組合比做一個軟體開發公司,那麼: * 專案立項及可研,由公司專案經理及顧問來完成 * 需求分析與設計,由產品經理和架構師來完成 * 程式碼研發,由專案經理帶領開發人員來完成 * 迭代測試,由測試團隊來完成 * 上線及配置管理、運維,可能由專門的devops團隊來完成 這樣一個公司內的所有人完成分工,就能在有限的資源的情況下,去接觸更多的客戶,談更多的需求,合理的分配人力資源,達到併發處理能力最大化的極限水平。相比於一個員工從頭到位的負責一個專案,它的組織性更強,分工更明確,合理的利用空閒資源,專業的人最專業的事。 這種人力資源的合理利用及組織方式和非阻塞IO模型有異曲同工之處,通過合理的將請求處理執行緒及任務進行分類,合理的利用系統的記憶體、CPU資源,達到單位時間內處理能力的最大化就是非同步非阻塞IO的核心用意! 回到上文給大家留下的問題,webClient處理單個HTTP請求的響應時長並不比RestTemplate更快,但是它處理併發的能力更強。**所以響應式非阻塞IO模型的核心意義在於:提高了單位時間內有限資源下的服務請求的併發處理能力,而不是縮短了單個服務請求的響應時長。** ## 二、WebClient 的優勢 上文為大家介紹完IO模型之後,我想大家已經可以明白了。與RestTemplate相比,WebClient優勢如下: * 非阻塞響應式IO,單位時間內有限資源下支援更高的併發量 * 支援使用Java 8 lambda表示式函式 * 同時支援同步、非同步與Streaming流式傳輸場景 ## 三、專案引入WebClient 使用WebClient需要引入如下的Jar(可以在包含`spring-boot-starter-web`的Spring Boot專案中引入) ~~~ ~~~ 那麼問題又來了,熟悉Spring 開發的朋友應該都知道。spring-boot-starter-webflux和spring-boot-starter-web代表的是兩套技術棧 * spring-boot-starter-web可以實現目前比較成熟的基於servlet技術棧的Spring Boot應用 * spring-boot-starter-webflux可以實現的是底層基於netty的響應式程式設計的技術棧的Spring Boot應用 二者可以共存麼?答案是: * 作為服務端實現Spring Boot應用而言,二者在應用角度當然是不能共存的。截止20200820我寫稿的時間,如果在一個專案裡面將二者都引入了,開發服務端應用其實使用的還是spring-boot-starter-web的基於servlet的技術棧。 * 作為HTTP客戶端而言,如果我們只是要使用WebClient。無論怎樣,引入`spring-boot-starter-webflux`就對了。 ## 四、WebClient 例項建立與基礎用法 建立WebClient有如下三種方式,我們來一一為大家介紹。 * `WebClient.create()` * `WebClient.create(String baseUrl)`:指定了baseUrl,使用該客戶端傳送請求都基於baseUrl * `WebClient.builder()`返回一個WebClient.Builder,該物件可以做鏈式呼叫,傳遞更多的引數。 > 為了方便後續開發測試,首先介紹一個網站給大家。[JSONPlaceholder](http://jsonplaceholder.typicode.com/)是一個提供免費的線上REST API的網站,我們在開發時可以使用它提供的url地址測試下網路請求以及請求引數。或者當我們程式需要獲取一些模擬資料、模擬圖片時也可以使用它。 ### 4.1. `WebClient.create()` 建立WebClient傳送GET請求,接收String型別單個Mono物件(Mono英文:單聲道、單體)。 ~~~ public class SimpleTest { @Test void testSimple() { WebClient webClient = WebClient.create();