筆者在以前已經寫了一系列的關於RestTemplate的文章,以下:html
RestTemplate
做爲spring-web項目的一部分,在Spring 3.0版本開始被引入。根據Spring官方文檔及源碼中的介紹,RestTemplate在未來的版本中它可能會被棄用, 做爲替代,Spring官方已在Spring 5中引入了WebClient做爲非阻塞式Reactive HTTP客戶端。
vue
在開始爲你們介紹webClient以前有必要爲你們介紹一下響應式非阻塞IO與傳統IO以前的區別。咱們先留下一個問題:webClient發送與接收單個HTTP請求比RestTemplate更快麼?答案是否認的。 看到這裏有的同窗已經蒙了,既然webClient沒有更快,那官方爲何還推薦使用它?聽我往下講。java
筆者用相對通俗的話爲你們說明一下阻塞IO與非阻塞IO之間的區別。咱們以軟件開發團隊的工做方式來作一個比喻。做爲軟件開發人員,咱們確定知道軟件開發的基本流程:web
在以Spring MVC或者struct爲表明的框架都是基於sevlet的,其底層IO模型是阻塞IO模型。這種模型就好像你是公司的一個開發人員,上面的全部的5項工做全都由你一我的完成。若是公司有10我的,最多就只能同時進行10個需求。客戶需求增多了也沒有辦法,只能讓他們等着。以下圖:一個請求佔用一個線程,當線程池內的線程都被佔用後新來的請求就只能等待。spring
spring 社區爲了解決Spring MVC的阻塞模型在高併發場景下的性能瓶頸的問題,推出了Spring WebFlux,WebFlux底層實現是久經考驗的netty非阻塞IO通訊框架。該框架的請求處理與線程交互關係圖以下:
boosGroup用於Accetpt鏈接創建事件並分發請求, workerGroup用於處理I/O讀寫事件。netty我就不細說了,仍是用通俗的方式給你們講一下:若是通俗的將上圖中的各個任務池、線程池的組合比作一個軟件開發公司,那麼:編程
這樣一個公司內的全部人完成分工,就能在有限的資源的狀況下,去接觸更多的客戶,談更多的需求,合理的分配人力資源,達到併發處理能力最大化的極限水平。相比於一個員工從頭到位的負責一個項目,它的組織性更強,分工更明確,合理的利用空閒資源,專業的人最專業的事。
這種人力資源的合理利用及組織方式和非阻塞IO模型有殊途同歸之處,經過合理的將請求處理線程及任務進行分類,合理的利用系統的內存、CPU資源,達到單位時間內處理能力的最大化就是異步非阻塞IO的核心用意! 回到上文給你們留下的問題,webClient處理單個HTTP請求的響應時長並不比RestTemplate更快,可是它處理併發的能力更強。因此響應式非阻塞IO模型的核心意義在於:提升了單位時間內有限資源下的服務請求的併發處理能力,而不是縮短了單個服務請求的響應時長。json
上文爲你們介紹完IO模型以後,我想你們已經能夠明白了。與RestTemplate相比,WebClient優點以下:後端
使用WebClient須要引入以下的Jar(能夠在包含spring-boot-starter-web
的Spring Boot項目中引入)springboot
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
那麼問題又來了,熟悉Spring 開發的朋友應該都知道。spring-boot-starter-webflux和spring-boot-starter-web表明的是兩套技術棧cookie
兩者能夠共存麼?答案是:
spring-boot-starter-webflux
就對了。建立WebClient有以下三種方式,咱們來一一爲你們介紹。
WebClient.create()
WebClient.create(String baseUrl)
:指定了baseUrl,使用該客戶端發送請求都基於baseUrlWebClient.builder()
返回一個WebClient.Builder,該對象能夠作鏈式調用,傳遞更多的參數。爲了方便後續開發測試,首先介紹一個網站給你們。JSONPlaceholder是一個提供免費的在線REST API的網站,咱們在開發時可使用它提供的url地址測試下網絡請求以及請求參數。或者當咱們程序須要獲取一些模擬數據、模擬圖片時也可使用它。
WebClient.create()
建立WebClient發送GET請求,接收String類型單個Mono對象(Mono英文:單聲道、單體)。
public class SimpleTest { @Test void testSimple() { WebClient webClient = WebClient.create(); Mono<String> mono = webClient .get() // 發送GET 請求 .uri("http://jsonplaceholder.typicode.com/posts/1") // 請求路徑 .retrieve() // 獲取響應結果 .bodyToMono(String.class); //響應數據類型轉換 System.out.println("=====" + mono.block()); } }
mono.block()方法仍然是阻塞式的數據響應接收方式,響應式的編程方法咱們後面文章會爲你們介紹。
WebClient.create(String baseUrl)
上面使用create()無參方法,在指定請求uri時每次都要指定完整的HTTP服務路徑,如"http://jsonplaceholder.typicode.com/posts/1"。使用WebClient.create(String baseUrl)
能夠統一指定一個baseUrl,這樣請求指定請求uri時,能夠省略baseUrl部分,如"/posts/1"。
private WebClient webClient = WebClient.create("http://jsonplaceholder.typicode.com"); @Test void testBaseUrl(){ Mono<String> mono = webClient .get() .uri("/posts/1") // 請求路徑,注意省略了baseurl部分 .retrieve() .bodyToMono(String.class); System.out.println("=====" + mono.block()); }
上面代碼請求結果,和4.1結果是同樣的
WebClient.builder()
使用builder()建立WebClient對象,能夠一次性傳遞的參數內容就更加豐富了。cookies、headers等信息均可以使用builder來傳遞。
場景:好比你請求的服務端使用JWT token,每次請求都須要傳遞token。若是每次請求都單獨去建立一個WebClient,而後指定Token,那就麻煩了。咱們可使用builder在WebClient實例化的時候,統一設置Token。
private WebClient webClient = WebClient .builder() .defaultHeader("JWT-Token", "xxxyyy3fsfsfsff-fjdskfa") .build();
支持的可選配置以下:
uriBuilderFactory
: 自定義UriBuilderFactory靈活配置使用UrldefaultHeader
: 爲HTTP請求設置Headers請求頭defaultCookie
: 爲HTTP請求設置CookiesdefaultRequest
: 自定義Http Requestfilter
: 爲HTTP請求增長客戶端過濾器exchangeStrategies
: HTTP 讀寫信息自定義clientConnector
: HTTP客戶端鏈接器設置以爲對您有幫助的話,幫我點贊、分享!您的支持是我不竭的創做動力! 。另外,筆者最近一段時間輸出了以下的精品內容,期待您的關注。