1.通過okhttp的核心思想構(gòu)建基本網(wǎng)絡(luò)請(qǐng)求庫(kù)咖为,具體pptx在以下鏈接:
鏈接:?https://pan.baidu.com/s/1JLA5yNctOdDCOghvWto3VA?
提取碼: szxf?
2.OkHttp框架中攔截器設(shè)計(jì)精髓之責(zé)任鏈模式
一疆液、責(zé)任鏈模式講解
1.1、責(zé)任鏈模式的特點(diǎn)
責(zé)任鏈模式可以使請(qǐng)求能被多個(gè)對(duì)象依次進(jìn)行處理,從而使這些對(duì)象形成一條完整的鏈路蝶怔,這樣就會(huì)使請(qǐng)求由起始點(diǎn)伟叛,順著這條鏈路,依次向下一個(gè)對(duì)象進(jìn)行傳遞淤击,直至傳遞到最后一個(gè)對(duì)象匠抗,責(zé)任鏈模式的應(yīng)用場(chǎng)景主要是以下幾種情況。
第一:當(dāng)一個(gè)請(qǐng)求可能會(huì)被某個(gè)環(huán)節(jié)修改污抬,并且該環(huán)節(jié)修改請(qǐng)求后汞贸,會(huì)將該請(qǐng)求繼續(xù)下發(fā)給下一個(gè)環(huán)節(jié)。
第二:請(qǐng)求處理環(huán)節(jié)可能會(huì)發(fā)生改變印机,有可能改變其中某個(gè)環(huán)節(jié)矢腻,也有可能所有的流程會(huì)發(fā)生更新,例如軟件項(xiàng)目中會(huì)發(fā)生一些流程規(guī)則改變射赛,甚至去掉某個(gè)流程多柑。通常,這種需求就需要將請(qǐng)求的處理環(huán)節(jié)楣责,由外部來(lái)決定竣灌,從而使高層接口抽象部分,在運(yùn)行時(shí)根據(jù)外部提供的具體實(shí)現(xiàn)秆麸,來(lái)實(shí)現(xiàn)多態(tài)調(diào)用初嘹。
第三:請(qǐng)求過程中,可能會(huì)存在重定向操作蛔屹、重試機(jī)制削樊,這種需求常出現(xiàn)在網(wǎng)絡(luò)框架中,為了確保網(wǎng)絡(luò)框架的健壯性,當(dāng)發(fā)生重定向漫贞,或進(jìn)行重試回滾時(shí)甸箱,就需要將請(qǐng)求中的部分參數(shù),進(jìn)行更新迅脐。
責(zé)任鏈模式的最大特點(diǎn)是芍殖,首先做到了對(duì)請(qǐng)求的依次向下傳遞,這樣使處理該請(qǐng)求的所有對(duì)象谴蔑,都可以共享到這個(gè)請(qǐng)求體豌骏。其次是責(zé)任鏈模式中用于處理請(qǐng)求的每個(gè)對(duì)象,并不需要關(guān)心該請(qǐng)求的上一個(gè)或下一個(gè)處理者隐锭,只需要將當(dāng)前處理的進(jìn)度窃躲,組織成請(qǐng)求處理者遵循的接口規(guī)范即可,并且確保請(qǐng)求處理者的響應(yīng)钦睡,也遵循統(tǒng)一的接口規(guī)范蒂窒,這樣就能使請(qǐng)求處理鏈路,在某一時(shí)刻一旦滿足客戶端需求時(shí)荞怒,能直接打斷洒琢,并將響應(yīng)結(jié)果反饋給客戶端。因此褐桌,使用責(zé)任鏈模式時(shí)衰抑,需要注意以下幾個(gè)方面。
1.2荧嵌、責(zé)任鏈模式設(shè)計(jì)思想
第一:由于一個(gè)請(qǐng)求會(huì)被多個(gè)處理者進(jìn)行處理呛踊,這就需要請(qǐng)求的處理者,接收請(qǐng)求時(shí)啦撮,需要遵循指定的接口規(guī)范恋技。而請(qǐng)求可能也會(huì)有多種不同的類型,因此逻族,這就需要對(duì)請(qǐng)求進(jìn)行抽象接口定義蜻底,而請(qǐng)求的抽象處理者在定義時(shí),接收請(qǐng)求的方法中對(duì)請(qǐng)求的依賴聘鳞,就需要定義為對(duì)請(qǐng)求接口的依賴薄辅。這樣一來(lái),請(qǐng)求接收者在接收請(qǐng)求時(shí)抠璃,就實(shí)現(xiàn)了接收與請(qǐng)求之間的松耦合站楚。
第二:由于責(zé)任鏈模式中,當(dāng)前處理者對(duì)請(qǐng)求進(jìn)行處理后搏嗡,會(huì)將響應(yīng)返回窿春。因此拉一,這就需要所有的請(qǐng)求處理者,返回的響應(yīng)頭旧乞,也要遵循統(tǒng)一的接口規(guī)范蔚润。
第三:請(qǐng)求處理者可能會(huì)存在多個(gè),具體處理者并不能確定尺栖,而且處理者的執(zhí)行順序不同嫡纠,常發(fā)生在流程改變,或某個(gè)流程規(guī)則發(fā)生替換時(shí)延赌。因此除盏,這就需要有一個(gè)容器,將所有的請(qǐng)求處理者進(jìn)行保存挫以,并且這個(gè)容器需要由客戶端傳遞過來(lái)者蠕。此外還要確保容器的數(shù)據(jù)類型,定義為請(qǐng)求處理者接口掐松,只有這樣蠢棱,容器中才可以添加不同類型的請(qǐng)求處理者。
第四:最后還要確保實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用甩栈,使容器中記錄的請(qǐng)求處理者,根據(jù)請(qǐng)求糕再,依次通過不同的請(qǐng)求處理者來(lái)處理請(qǐng)求量没。所以,接下來(lái)還需要提供一個(gè)專門用于執(zhí)行請(qǐng)求處理者的執(zhí)行鏈突想。
執(zhí)行鏈需要記錄客戶端指定的所有請(qǐng)求處理者殴蹄,并記錄當(dāng)前請(qǐng)求處理者的光標(biāo)索引,同時(shí)還需要記錄客戶端請(qǐng)求猾担。這樣一來(lái)袭灯,當(dāng)執(zhí)行鏈被觸發(fā)時(shí),會(huì)在觸發(fā)調(diào)用的方法中绑嘹,再次創(chuàng)建一個(gè)執(zhí)行鏈next稽荧,并為這個(gè)next定義光標(biāo)值+1,這就會(huì)使next這個(gè)執(zhí)行鏈被執(zhí)行時(shí)工腋,從處理者容器中獲取下一個(gè)處理者并將其執(zhí)行姨丈,而這下一個(gè)處理者,會(huì)再次創(chuàng)建一個(gè)執(zhí)行鏈擅腰,并在此基礎(chǔ)上更新光標(biāo)數(shù)值蟋恬。這樣一來(lái),執(zhí)行鏈會(huì)被多次創(chuàng)建趁冈,而每次創(chuàng)建執(zhí)行時(shí)歼争,都會(huì)訪問獲取處理者容器中的下一個(gè)元素拜马,并將該元素執(zhí)行,這樣就將容器中的所有處理者沐绒,以鏈的方式一一執(zhí)行俩莽。每個(gè)處理者元素,都將會(huì)返回響應(yīng)洒沦,由于這時(shí)已經(jīng)確保所有處理者按照在容器中的順序一一執(zhí)行豹绪,因此,按照順序?qū)㈨憫?yīng)進(jìn)行拼接申眼,這就形成了客戶端請(qǐng)求按照順序瞒津,逐一被請(qǐng)求處理者執(zhí)行,并最終將響應(yīng)結(jié)果拼接括尸,從而就實(shí)現(xiàn)了通過責(zé)任鏈模式的鏈?zhǔn)秸{(diào)用巷蚪。
1.3、責(zé)任鏈模式攔截器在OKHttp中的使用
在OKHttp框架的RealCall的execute方法中濒翻,會(huì)提交客戶端請(qǐng)求到線程池中屁柏,從而實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求。在execute方法中有送,getResponseWithInterceptorChain方法淌喻,就是OKHttp框架中對(duì)攔截器的調(diào)用部分,這個(gè)方法返回了Response響應(yīng)雀摘,而響應(yīng)就是根據(jù)getResponseWithInterceptorChain方法中執(zhí)行的所有攔截器的返回結(jié)果裸删,進(jìn)行拼接而成的。接下來(lái)進(jìn)入該方法查看一下攔截器是如何實(shí)現(xiàn)并調(diào)用的阵赠。
在getResponseWithInterceptorChain方法中涯塔,首先創(chuàng)建了一個(gè)interceptors容器,然后分別將客戶端自定義清蚀、請(qǐng)求重試匕荸、橋接、緩存枷邪、連接等不同職責(zé)的攔截器榛搔,依次添加到了這個(gè)容器中,每個(gè)攔截器就相當(dāng)于責(zé)任鏈上對(duì)請(qǐng)求的不同處理者东揣。最后药薯,創(chuàng)建了一個(gè)RealInterceptorChain攔截鏈,并將interceptors容器救斑、當(dāng)前光標(biāo)位置和客戶端傳遞過來(lái)的請(qǐng)求Request童本,添加到了這個(gè)攔截鏈中,并通過RealInterceptorChain的proceed方法觸發(fā)攔截鏈脸候,使每個(gè)攔截器被依次執(zhí)行穷娱,代碼如下所示绑蔫。
在OKHttp網(wǎng)絡(luò)請(qǐng)求框架中,攔截器Interceptor是該框架的設(shè)計(jì)精髓泵额,也是對(duì)責(zé)任鏈模式的一個(gè)經(jīng)典應(yīng)用配深。這里將網(wǎng)絡(luò)請(qǐng)求中的每個(gè)環(huán)節(jié)的處理者,定義了統(tǒng)一的Interceptor攔截器接口嫁盲,使每個(gè)環(huán)節(jié)的實(shí)現(xiàn)篓叶,都是基于Interceptor接口規(guī)范來(lái)完成的。通過這種設(shè)計(jì)思想羞秤,也使得每個(gè)環(huán)節(jié)更加獨(dú)立缸托,職責(zé)更單一。
接下來(lái)我們分析OKHttp框架中攔截器鏈?zhǔn)秸{(diào)用設(shè)計(jì)是如何實(shí)現(xiàn)的瘾蛋。我們根據(jù)OKHttp框架的Interceptor俐镐、RealInterceptorChain,自己設(shè)計(jì)一個(gè)與該框架類似的攔截器應(yīng)用哺哼,通過模擬緩存訪問佩抹、連接到服務(wù)器、處理服務(wù)器返回?cái)?shù)據(jù)等取董,來(lái)看看如何通過責(zé)任鏈模式棍苹,實(shí)現(xiàn)攔截器鏈?zhǔn)秸{(diào)用。
1.4茵汰、通過責(zé)任鏈模式實(shí)現(xiàn)攔截器
1.4.1枢里、定義攔截器抽象接口層
先來(lái)回顧一下前面關(guān)于對(duì)責(zé)任鏈模式設(shè)計(jì)思想概括的前兩點(diǎn),前兩點(diǎn)中強(qiáng)調(diào)了實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用的前提條件经窖,要確保接收的請(qǐng)求和返回的響應(yīng),遵循統(tǒng)一的接口規(guī)范梭灿。只有這樣画侣,攔截器與攔截器之間,才能進(jìn)行請(qǐng)求的向下派發(fā)或回滾堡妒,以及響應(yīng)結(jié)果的拼接配乱。
鏈?zhǔn)秸{(diào)用還需要確保每個(gè)攔截器接收到攔截鏈執(zhí)行器,并在攔截器中調(diào)用執(zhí)行器中的方法皮迟,從而使執(zhí)行器再次創(chuàng)建搬泥,并使攔截器光標(biāo)定位到下一個(gè)節(jié)點(diǎn),從而觸發(fā)下一個(gè)節(jié)點(diǎn)的攔截器伏尼。以此類推忿檩,最終形成一整套的鏈?zhǔn)秸{(diào)用。
因此爆阶,定義攔截器抽象層時(shí)燥透,需要提供兩個(gè)接口沙咏,代碼如下所示。
Interceptor是對(duì)攔截器的抽象接口定義班套,在intercept方法中肢藐,將會(huì)接收一個(gè)Chain。而Chain就是攔截鏈的抽象定義吱韭,這樣一來(lái)吆豹,當(dāng)攔截器的具體實(shí)現(xiàn)在調(diào)用intercept方法時(shí),就可以通過Chain攔截鏈理盆,調(diào)用request方法取出客戶端請(qǐng)求痘煤,然后再調(diào)用process方法從而創(chuàng)建下一個(gè)節(jié)點(diǎn)的Chain,這時(shí)熏挎,在下一個(gè)節(jié)點(diǎn)的Chain中速勇,將會(huì)定位到下一個(gè)Interceptor攔截器。由此類推坎拐,直至最后一個(gè)攔截器Interceptor烦磁,不再執(zhí)行Chain的process方法。因?yàn)閳?zhí)行到最后一個(gè)攔截器時(shí)哼勇,后面不再有攔截器都伪,所以在最后一個(gè)攔截器調(diào)用后,就需要將最終的響應(yīng)結(jié)果积担,反饋給客戶端了陨晶。
1.4.2、實(shí)現(xiàn)攔截鏈RealInterceptorChain
以上內(nèi)容對(duì)攔截器及攔截鏈的抽象層進(jìn)行了分析帝璧,接下來(lái)我們分析攔截鏈(Chain接口的具體實(shí)現(xiàn))是如何實(shí)現(xiàn)攔截器被依次按順序從第1個(gè)元素開始先誉,執(zhí)行到最后一個(gè)元素的。
回顧責(zé)任鏈模式的特點(diǎn)及設(shè)計(jì)思想的烁,處理者的數(shù)量并不確定褐耳,也就是說,某個(gè)環(huán)節(jié)的處理過程渴庆,可能會(huì)隨時(shí)發(fā)生改變铃芦,也可能整個(gè)處理流程都會(huì)發(fā)生變更。因此襟雷,對(duì)于攔截鏈的具體實(shí)現(xiàn)RealInterceptorChain來(lái)說刃滓,不能在其內(nèi)部定義攔截器的具體實(shí)現(xiàn),而是需要接收一個(gè)從客戶端傳入的攔截器集合耸弄。只有這樣咧虎,當(dāng)RealInterceptorChain被攔截器再次觸發(fā)創(chuàng)建時(shí),就可以根據(jù)當(dāng)前攔截器集合以及光標(biāo)索引计呈,獲取到下一個(gè)攔截器老客,并將其執(zhí)行僚饭,最終形成鏈?zhǔn)秸{(diào)用。
以下是RealInterceptorChain的構(gòu)造方法胧砰,創(chuàng)建時(shí)通過接收客戶端指定的攔截器集合鳍鸵、光標(biāo)和請(qǐng)求,可以確保RealInterceptorChain在process方法被執(zhí)行時(shí)尉间,能根據(jù)客戶端請(qǐng)求request偿乖,以及光標(biāo)index和interceptors容器,獲取當(dāng)前這個(gè)節(jié)點(diǎn)的Interceptor攔截器哲嘲,并通過對(duì)光標(biāo)index+1的方式贪薪,創(chuàng)建用于執(zhí)行下一個(gè)Interceptor攔截器的RealInterceptorChain。
接下來(lái)執(zhí)行當(dāng)前攔截器的intercept方法眠副,并將下一個(gè)節(jié)點(diǎn)的RealInterceptorChain傳入画切,就可以確保當(dāng)前攔截器的具體實(shí)現(xiàn)中,可以根據(jù)傳入的RealInterceptorChain囱怕,再次執(zhí)行process方法霍弹,從而依次迭代,使每個(gè)攔截器都被執(zhí)行娃弓。
在process方法中典格,每次調(diào)用該方法時(shí)都會(huì)創(chuàng)建RealInterceptorChain的next對(duì)象,并根據(jù)當(dāng)前index光標(biāo)索引台丛,取出當(dāng)前攔截器耍缴,執(zhí)行intercept方法,并傳入next挽霉。這樣一來(lái)就可以在具體的Interceptor攔截器中防嗡,來(lái)決定是否需要繼續(xù)調(diào)用RealInterceptorChain對(duì)象的process方法。如果繼續(xù)調(diào)用此方法侠坎,則框架會(huì)繼續(xù)執(zhí)行下一個(gè)節(jié)點(diǎn)的攔截器蚁趁,否則,將會(huì)終止硅蹦,并直接向客戶端返回結(jié)果荣德。
1.4.3闷煤、攔截器的具體實(shí)現(xiàn)
對(duì)于一個(gè)復(fù)雜的網(wǎng)絡(luò)請(qǐng)求框架來(lái)說童芹,按每個(gè)不同的流程進(jìn)行拆分,可以拆分為緩存鲤拿、連接假褪、重試或重定向、處理服務(wù)器返回?cái)?shù)據(jù)等多個(gè)不同的環(huán)節(jié)近顷。由于前面的內(nèi)容中生音,我們通過對(duì)攔截器以及請(qǐng)求宁否、響應(yīng)的接口規(guī)范進(jìn)行定義,已經(jīng)可以確保這些流程環(huán)節(jié)缀遍,均遵循統(tǒng)一的接口協(xié)議慕匠。因此,接下來(lái)通過實(shí)現(xiàn)不同的攔截器域醇,為后面的代碼測(cè)試進(jìn)行準(zhǔn)備台谊。
再來(lái)回顧一下關(guān)于Interceptor攔截器接口的特點(diǎn)和作用,通過面向接口編程譬挚,主要帶來(lái)了以下這些優(yōu)勢(shì)锅铅。
結(jié)合前面分析的RealInterceptorChain構(gòu)造方法以及RealInterceptorChain中的process方法,發(fā)現(xiàn)在RealInterceptorChain攔截鏈中减宣,只有創(chuàng)建下一節(jié)點(diǎn)攔截鏈盐须、獲取當(dāng)前攔截器、執(zhí)行當(dāng)前攔截器并返回結(jié)果的方法漆腌,這里并沒有對(duì)攔截器的具體實(shí)現(xiàn)產(chǎn)生依賴贼邓,其攔截器容器中定義的泛型,都是對(duì)Interceptor這個(gè)抽象接口產(chǎn)生的依賴屉凯。
這樣的設(shè)計(jì)就實(shí)現(xiàn)了攔截鏈RealInterceptorChain與客戶端調(diào)用之間的松耦合立帖,即使某個(gè)攔截器發(fā)生了改變,或流程順序發(fā)生改變等悠砚,RealInterceptorChain都不需要進(jìn)行任何調(diào)整晓勇。這就確保了核心的攔截鏈代碼的穩(wěn)定性和健壯性,無(wú)論客戶端提供的容器中包含多少個(gè)攔截器灌旧,RealInterceptorChain都能正常處理绑咱,并逐一使這些攔截器被鏈?zhǔn)秸{(diào)用。
以下是緩存攔截器CacheInterceptor枢泰,這個(gè)攔截器在執(zhí)行時(shí)模擬了檢查緩存操作描融,為了能看到模擬網(wǎng)絡(luò)請(qǐng)求的過程,使網(wǎng)絡(luò)連接衡蚂、解析服務(wù)器響應(yīng)的攔截器依次被執(zhí)行窿克,在這個(gè)緩存攔截器中,通過RealInterceptorChain的process方法毛甲,使下一個(gè)攔截器執(zhí)行年叮。
網(wǎng)絡(luò)連接的攔截器模擬了連接到服務(wù)器的操作,接下來(lái)通過RealInterceptorChain的process方法玻募,使解析服務(wù)器響應(yīng)數(shù)據(jù)的攔截器被執(zhí)行只损。
解析服務(wù)器響應(yīng)數(shù)據(jù)的攔截器,模擬解析數(shù)據(jù)后,通過RealInterceptorChain使下一個(gè)攔截器執(zhí)行跃惫。
ResultCallBackInterceptor為最后一個(gè)攔截器叮叹,因此,這里直接向客戶端返回響應(yīng)數(shù)據(jù)爆存,不再通過RealInterceptorChain派發(fā)請(qǐng)求了蛉顽。
1.4.4、攔截器在客戶端的調(diào)用?
接下來(lái)在測(cè)試類中測(cè)試攔截器的執(zhí)行先较,首先按照先后執(zhí)行順序蜂林,依次將不同的攔截器,添加到容器中拇泣,然后創(chuàng)建攔截鏈噪叙,并傳入客戶端的請(qǐng)求、以及客戶端定義的容器和光標(biāo)霉翔,最后通過調(diào)用process方法睁蕾,觸發(fā)鏈?zhǔn)秸{(diào)用。
程序執(zhí)行結(jié)果如下圖所示债朵,通過觀察運(yùn)行結(jié)果就可以看出子眶,RealInterceptorChain根據(jù)客戶端指定的所有攔截器,按照先后順序序芦,依次執(zhí)行臭杰,并最終將結(jié)果反饋給客戶端。?
來(lái)源:CSDN
原文:https://blog.csdn.net/qq_15274383/article/details/78485648