okhttp淺析

轉載自:http://www.ishenping.com/ArtInfo/69561.html

一、okhttp工做的大體流程

1.一、總體流程

(1)、當咱們經過OkhttpClient建立一個Call,併發起同步或異步請求時;
(2)、okhttp會經過Dispatcher對咱們全部的RealCall(Call的具體實現類)進行統一管理,並經過execute()及enqueue()方法對同步或異步請求進行處理;
(3)、execute()及enqueue()這兩個方法會最終調用RealCall中的getResponseWithInterceptorChain()方法,從攔截器鏈中獲取返回結果;
(4)、攔截器鏈中,依次經過RetryAndFollowUpInterceptor(重定向攔截器)、BridgeInterceptor(橋接攔截器)、CacheInterceptor(緩存攔截器)、ConnectInterceptor(鏈接攔截器)、CallServerInterceptor(網絡攔截器)對請求依次處理,與服務的創建鏈接後,獲取返回數據,再通過上述攔截器依次處理後,最後將結果返回給調用方。
提供兩張圖便於理解和記憶:html

 

 
6024478-fcfb26ca04a78fbc.png
okhttp總體流程1
 
6024478-80d45f4fcc34489e.png
okhttp總體流程2

 

這張圖只畫出了請求流程,沒有數據返回流程,後期會處理。面試

1.二、各大攔截器的原理解析

1.2.一、RetryAndFollowUpInterceptor:負責重定向

構建一個StreamAllocation對象,而後調用下一個攔截器獲取結果,從返回結果中獲取重定向的request,若是重定向的request不爲空的話,而且不超太重定向最大次數的話就進行重定向,不然返回結果。注意:這裏是經過一個while(true)的循環完成下一輪的重定向請求。緩存

(1)、StreamAllocation爲何在第一個攔截器中就進行建立?
???????便於取消請求以及出錯釋放資源。
(2)、StreamAllocation的做用是什麼?
???????StreamAllocation負責統籌管理Connection、Stream、Call三個實體類,具體就是爲一個Call(Realcall),尋找( findConnection() )一個Connection(RealConnection),獲取一個Stream(HttpCode)。服務器

1.2.二、BridgeInterceptor

負責將原始Requset轉換給發送給服務端的Request以及將Response轉化成對調用方友好的Response,具體就是對request添加Content-Type、Content-Length、Connection、Accept-Encoding等請求頭以及對返回結果進行解壓等。網絡

1.2.三、CacheInterceptor

CacheInterceptor:負責讀取緩存以及更新緩存。
在請求階段:併發

  1. 讀取候選緩存cacheCandidate;
  2. 根據originOequest和cacheresponse建立緩存策略CacheStrategy;
  3. 根據緩存策略,來決定是否使用網絡或者使用緩存或者返回錯誤。
    具體的的緩存策略就是http的緩存策略,詳見下圖:
    在結果返回階段:
    負責將網絡結果進行緩存(使用於DiskLruCache)。
 
6024478-bcb83a4dccb3a2c4.png
okhttp&http緩存策略

強制緩存:當客戶端第一次請求數據是,服務端返回了緩存的過時時間(Expires與Cache-Control),沒有過時就能夠繼續使用緩存,不然則不適用,無需再向服務端詢問。
對比緩存:當客戶端第一次請求數據時,服務端會將緩存標識(Etag/If-None-Match與Last-Modified/If-Modified-Since)與數據一塊兒返回給客戶端,客戶端將二者都備份到緩存中 ,再次請求數據時,客戶端將上次備份的緩存
標識發送給服務端,服務端根據緩存標識進行判斷,若是返回304,則表示緩存可用,若是返回200,標識緩存不可用,使用最新返回的數據。異步

ETag是用資源標識碼標識資源是否被修改,Last-Modified是用時間戳標識資源是否被修改。ETag優先級高於Last-Modified。socket

1.2.四、ConnectInterceptor:負責與服務器創建鏈接

使用StreamAllocation.newStream來和服務端創建鏈接,並返回輸入輸出流(HttpCodec),其實是經過StreamAllocation中的findConnection尋找一個可用的Connection,而後調用Connection的connect方法,使用socket與服務端創建鏈接。post

1.2.五、CallServerInterceptor:負責從服務器讀取響應的數據

主要的工做就是把請求的Request寫入到服務端,而後從服務端讀取Response。
(1)、寫入請求頭
(2)、寫入請求體
(3)、讀取響應頭
(4)、讀取響應體spa

二、鏈接池原理

因爲HTTP是基於TCP,TCP鏈接時須要通過三次握手,爲了加快網絡訪問速度,咱們能夠Reuqst的header中將Connection設置爲keepalive來複用鏈接。

Okhttp支持5個併發KeepAlive,默認鏈路生命爲5分鐘(鏈路空閒後,保持存活的時間),鏈接池有ConectionPool實現,對鏈接進行回收和管理。

2.一、鏈接池的清理

 
6024478-b2d3dfc5542b4cce.png
鏈接池清理1

 

在ConectionPool中有一個異步線程去清理鏈接池中的鏈接,首先經過cleanup方法執行清理,而後等待clean返回的時間後,再次進行清理,以此循環,持續清理。

 
6024478-da5bf326653b7671.png
鏈接池原理2

一、首先統計空閒鏈接數量;
二、而後經過for循環查找最長空閒時間的鏈接以及對應空閒時長;
三、而後判斷這個最長空閒時間的鏈接是否超出最大空閒鏈接數或者或者超過最大空閒時間,知足其一則清除最長空閒的鏈接。若是不知足清理條件,則返回一個對應等待時間。
這個對應等待的時間又分二種狀況:
1 有空閒鏈接:則返回:keepAliveDurationNs-longestIdleDurationNs;
2 沒有空閒的鏈接,則返回:keepAliveDurationNs
注意:清除一個空閒鏈接後,會返回0,再次當即開始清理。

如何統計空閒鏈接呢?

 

 
6024478-076bec66f5dd894f.png
統計空閒鏈接

 

StreamAllocation建立一個Connection後會將本身添加到Connection的connection.allocations列表中,數據讀取完畢以後,會將本身從Connection的connection.allocations中移除,因此判讀一個Connection是不是空閒鏈接能夠採用引用計數法,判斷connection.allocations列表中是否有StreamAllocation,若是沒有就是空閒鏈接,不然不是。

三、參考連接

由於本文是極度針對面試的,因此未解釋過多名詞和粘貼過多代碼,若是不明白其中原理,能夠參考下面兩篇連接:
3.一、https://www.jianshu.com/p/6166d28983a2
3.二、http://www.javashuo.com/article/p-mvwpcnbi-hs.html

相關文章
相關標籤/搜索