這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)響應(yīng)式非阻塞IO與基礎(chǔ)用法是什么,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
專注于為中小企業(yè)提供網(wǎng)站建設(shè)、網(wǎng)站制作服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)曹縣免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上千企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
RestTemplate
作為spring-web項(xiàng)目的一部分,在Spring 3.0版本開始被引入。根據(jù)Spring官方文檔及源碼中的介紹,RestTemplate在將來的版本中它可能會(huì)被棄用, 作為替代,Spring官方已在Spring 5中引入了WebClient作為非阻塞式Reactive HTTP客戶端。
在開始為大家介紹webClient之前有必要為大家介紹一下響應(yīng)式非阻塞IO與傳統(tǒng)IO之前的區(qū)別。我們先留下一個(gè)問題:webClient發(fā)送與接收單個(gè)HTTP請(qǐng)求比RestTemplate更快么?答案是否定的。看到這里有的同學(xué)已經(jīng)蒙了,既然webClient沒有更快,那官方為什么還推薦使用它?聽我往下講。
筆者用相對(duì)通俗的話為大家說明一下阻塞IO與非阻塞IO之間的區(qū)別。我們以軟件開發(fā)團(tuán)隊(duì)的工作方式來做一個(gè)比喻。作為軟件開發(fā)人員,我們肯定知道軟件開發(fā)的基本流程:
項(xiàng)目立項(xiàng)與可行性研究
需求分析與設(shè)計(jì)
代碼開發(fā)
迭代測(cè)試
上線及配置管理、運(yùn)維
在以Spring MVC或者struct為代表的框架都是基于sevlet的,其底層IO模型是阻塞IO模型。這種模型就好像你是公司的一個(gè)開發(fā)人員,上面的所有的5項(xiàng)工作全都由你一個(gè)人完成。如果公司有10個(gè)人,最多就只能同時(shí)進(jìn)行10個(gè)需求??蛻粜枨笤龆嗔艘矝]有辦法,只能讓他們等著。如下圖:一個(gè)請(qǐng)求占用一個(gè)線程,當(dāng)線程池內(nèi)的線程都被占用后新來的請(qǐng)求就只能等待。
spring 社區(qū)為了解決Spring MVC的阻塞模型在高并發(fā)場(chǎng)景下的性能瓶頸的問題,推出了Spring WebFlux,WebFlux底層實(shí)現(xiàn)是久經(jīng)考驗(yàn)的netty非阻塞IO通信框架。該框架的請(qǐng)求處理與線程交互關(guān)系圖如下:
boosGroup用于Accetpt連接建立事件并分發(fā)請(qǐng)求, workerGroup用于處理I/O讀寫事件。netty我就不細(xì)說了,還是用通俗的方式給大家講一下:如果通俗的將上圖中的各個(gè)任務(wù)池、線程池的組合比做一個(gè)軟件開發(fā)公司,那么:
項(xiàng)目立項(xiàng)及可研,由公司項(xiàng)目經(jīng)理及顧問來完成
需求分析與設(shè)計(jì),由產(chǎn)品經(jīng)理和架構(gòu)師來完成
代碼研發(fā),由項(xiàng)目經(jīng)理帶領(lǐng)開發(fā)人員來完成
迭代測(cè)試,由測(cè)試團(tuán)隊(duì)來完成
上線及配置管理、運(yùn)維,可能由專門的devops團(tuán)隊(duì)來完成
這樣一個(gè)公司內(nèi)的所有人完成分工,就能在有限的資源的情況下,去接觸更多的客戶,談更多的需求,合理的分配人力資源,達(dá)到并發(fā)處理能力最大化的極限水平。相比于一個(gè)員工從頭到位的負(fù)責(zé)一個(gè)項(xiàng)目,它的組織性更強(qiáng),分工更明確,合理的利用空閑資源,專業(yè)的人最專業(yè)的事。
這種人力資源的合理利用及組織方式和非阻塞IO模型有異曲同工之處,通過合理的將請(qǐng)求處理線程及任務(wù)進(jìn)行分類,合理的利用系統(tǒng)的內(nèi)存、CPU資源,達(dá)到單位時(shí)間內(nèi)處理能力的最大化就是異步非阻塞IO的核心用意! 回到上文給大家留下的問題,webClient處理單個(gè)HTTP請(qǐng)求的響應(yīng)時(shí)長(zhǎng)并不比RestTemplate更快,但是它處理并發(fā)的能力更強(qiáng)。所以響應(yīng)式非阻塞IO模型的核心意義在于:提高了單位時(shí)間內(nèi)有限資源下的服務(wù)請(qǐng)求的并發(fā)處理能力,而不是縮短了單個(gè)服務(wù)請(qǐng)求的響應(yīng)時(shí)長(zhǎng)。
上文為大家介紹完IO模型之后,我想大家已經(jīng)可以明白了。與RestTemplate相比,WebClient優(yōu)勢(shì)如下:
非阻塞響應(yīng)式IO,單位時(shí)間內(nèi)有限資源下支持更高的并發(fā)量
支持使用Java 8 lambda表達(dá)式函數(shù)
同時(shí)支持同步、異步與Streaming流式傳輸場(chǎng)景
使用WebClient需要引入如下的Jar(可以在包含spring-boot-starter-web
的Spring Boot項(xiàng)目中引入)
org.springframework.boot spring-boot-starter-webflux
那么問題又來了,熟悉Spring 開發(fā)的朋友應(yīng)該都知道。spring-boot-starter-webflux和spring-boot-starter-web代表的是兩套技術(shù)棧
spring-boot-starter-web可以實(shí)現(xiàn)目前比較成熟的基于servlet技術(shù)棧的Spring Boot應(yīng)用
spring-boot-starter-webflux可以實(shí)現(xiàn)的是底層基于netty的響應(yīng)式編程的技術(shù)棧的Spring Boot應(yīng)用
二者可以共存么?答案是:
作為服務(wù)端實(shí)現(xiàn)Spring Boot應(yīng)用而言,二者在應(yīng)用角度當(dāng)然是不能共存的。截止20200820我寫稿的時(shí)間,如果在一個(gè)項(xiàng)目里面將二者都引入了,開發(fā)服務(wù)端應(yīng)用其實(shí)使用的還是spring-boot-starter-web的基于servlet的技術(shù)棧。
作為HTTP客戶端而言,如果我們只是要使用WebClient。無論怎樣,引入spring-boot-starter-webflux
就對(duì)了。
創(chuàng)建WebClient有如下三種方式,我們來一一為大家介紹。
WebClient.create()
WebClient.create(String baseUrl)
:指定了baseUrl,使用該客戶端發(fā)送請(qǐng)求都基于baseUrl
WebClient.builder()
返回一個(gè)WebClient.Builder,該對(duì)象可以做鏈?zhǔn)秸{(diào)用,傳遞更多的參數(shù)。
為了方便后續(xù)開發(fā)測(cè)試,首先介紹一個(gè)網(wǎng)站給大家。JSONPlaceholder是一個(gè)提供免費(fèi)的在線REST API的網(wǎng)站,我們?cè)陂_發(fā)時(shí)可以使用它提供的url地址測(cè)試下網(wǎng)絡(luò)請(qǐng)求以及請(qǐng)求參數(shù)?;蛘弋?dāng)我們程序需要獲取一些模擬數(shù)據(jù)、模擬圖片時(shí)也可以使用它。
WebClient.create()
創(chuàng)建WebClient發(fā)送GET請(qǐng)求,接收String類型單個(gè)Mono對(duì)象(Mono英文:?jiǎn)温暤?、單體)。
public class SimpleTest { [@Test](https://my.oschina.net/azibug) void testSimple() { WebClient webClient = WebClient.create(); Monomono = webClient .get() // 發(fā)送GET 請(qǐng)求 .uri("http://jsonplaceholder.typicode.com/posts/1") // 請(qǐng)求路徑 .retrieve() // 獲取響應(yīng)結(jié)果 .bodyToMono(String.class); //響應(yīng)數(shù)據(jù)類型轉(zhuǎn)換 System.out.println("=====" + mono.block()); } }
mono.block()方法仍然是阻塞式的數(shù)據(jù)響應(yīng)接收方式,響應(yīng)式的編程方法我們后面文章會(huì)為大家介紹。
WebClient.create(String baseUrl)
上面使用create()無參方法,在指定請(qǐng)求uri時(shí)每次都要指定完整的HTTP服務(wù)路徑,如"http://jsonplaceholder.typicode.com/posts/1"。使用WebClient.create(String baseUrl)
可以統(tǒng)一指定一個(gè)baseUrl,這樣請(qǐng)求指定請(qǐng)求uri時(shí),可以省略baseUrl部分,如"/posts/1"。
private WebClient webClient = WebClient.create("http://jsonplaceholder.typicode.com"); [@Test](https://my.oschina.net/azibug) void testBaseUrl(){ Monomono = webClient .get() .uri("/posts/1") // 請(qǐng)求路徑,注意省略了baseurl部分 .retrieve() .bodyToMono(String.class); System.out.println("=====" + mono.block()); }
上面代碼請(qǐng)求結(jié)果,和4.1結(jié)果是一樣的
WebClient.builder()
使用builder()創(chuàng)建WebClient對(duì)象,可以一次性傳遞的參數(shù)內(nèi)容就更加豐富了。cookies、headers等信息都可以使用builder來傳遞。 場(chǎng)景:比如你請(qǐng)求的服務(wù)端使用JWT token,每次請(qǐng)求都需要傳遞token。如果每次請(qǐng)求都單獨(dú)去創(chuàng)建一個(gè)WebClient,然后指定Token,那就麻煩了。我們可以使用builder在WebClient實(shí)例化的時(shí)候,統(tǒng)一設(shè)置Token。
private WebClient webClient = WebClient .builder() .defaultHeader("JWT-Token", "xxxyyy3fsfsfsff-fjdskfa") .build();
支持的可選配置如下:
uriBuilderFactory
: 自定義UriBuilderFactory靈活配置使用Url
defaultHeader
: 為HTTP請(qǐng)求設(shè)置Headers請(qǐng)求頭
defaultCookie
: 為HTTP請(qǐng)求設(shè)置Cookies
defaultRequest
: 自定義Http Request
filter
: 為HTTP請(qǐng)求增加客戶端過濾器
exchangeStrategies
: HTTP 讀寫信息自定義
clientConnector
: HTTP客戶端連接器設(shè)置
上述就是小編為大家分享的響應(yīng)式非阻塞IO與基礎(chǔ)用法是什么了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。