本系列文章:
OkHttp源碼徹底解析(三)OkHttp3.0攔截器原理——責任鏈模式
目錄
連接池是用來管理和複用網絡連接對象的,而網絡連接的主角就是Connection/RealConnection.
OkHttp連接池
OkHttp3將客戶端與服務器之間的連接抽象爲Connection/RealConnection,爲了管理這些連接的複用而設計了ConnectionPool。共享相同Address
的請求可以複用連接
連接池的意義——KeepAlive機制
複用連接,減少了頻繁的網絡請求導致性能下降的問題。我們知道,Http是基於TCP協議的,而TCP建立連接需要經過三次握手,斷開需要經過四次揮手,因此,Http中添加了一種KeepAlive機制,當數據傳輸完畢後仍然保持連接,等待下一次請求時直接複用該連接。
一次響應的流程
在高併發的請求連接情況下或者同個客戶端多次頻繁的請求操作,無限制的創建會導致性能低下。
如果使用keep-alive
在timeout
空閒時間內,連接不會關閉,相同重複的request將複用原先的connection
,減少握手的次數,大幅提高效率。
並非
keep-alive
的timeout設置時間越長,就越能提升性能。長久不關閉會造成過多的殭屍連接和泄露連接出現。
從攔截器流程瞭解連接池
在講解連接池之前,先了解OkHttp的攔截器
OkHttp攔截器流程圖
上面的攔截器分別是:
1.失敗重連攔截器:
一個循環來不停的獲取response。每循環一次都會獲取下一個request,如果沒有,則返回response,退出循環。而獲取下一個request的邏輯,是根據上一個response返回的狀態碼,分別作處理。
2.橋接攔截器:
請求從應用層數據類型類型轉化爲網絡調用層的數據類型。將網絡層返回的數據類型 轉化爲 應用層數據類型。(補足缺失的請求頭等)
3.緩存攔截器:
CacheInterceptor主要作用是將請求 和 返回 關連得保存到緩存中。客戶端與服務端根據一定的機制,在需要的時候使用緩存的數據作爲網絡請求的響應,節省了時間和帶寬。
4.連接攔截器
與請求服務器的攔截器是網絡交互的關鍵。爲請求服務器攔截器建立可用的連接,創建用於網絡IO流 的RealConnection對象
5.請求服務器的攔截器:
完成了最後發起網絡請求的工作。將HTTP請求寫入網絡IO流,從IO流讀取網絡數據。
與連接攔截器要劃分爲兩個攔截器,除了解耦之外,更重要的是在這兩個流程之間還可以插入一個專門爲WebSocket服務的攔截器( WebSocket一種在單個 TCP 連接上進行全雙工通訊的協議,本文不做詳解)。
關於這部分不具體展開,感興趣可以看我的另外兩篇博客,可以說是非常詳細地介紹了攔截器的原理及應用
其中,與連接池相關的是失敗重連攔截器與連接攔截器
1.RetryAndFollowUpInterceptor將創建的StreamAllocation
對象傳遞給後面執行的Interceptor
2.ConnectInterceptor
從RealInterceptorChain
獲取前面的Interceptor傳過來的StreamAllocation
對象,執行 streamAllocation.newStream()
完成前述所有的連接建立工作,創建的用於網絡IO的RealConnection對象,以及對於與服務器交互最爲關鍵的HttpCodec等對象傳遞給後面的Interceptor,也就是CallServerInterceptor
。
streamAllocation.newStream()新建了IO流,將請求序列化發到網絡,將網絡數據反序列化並接收
(請求服務器的攔截器)。
RealConnection底層連接着Socket,就是實現了跨進程與網絡上其他設備交互的底層實現。
連接池ConnectionPool的創建
OkHttp3的用戶可以自行創建ConnectionPool,對最大空閒連接數及連接的保活時間進行配置,並在OkHttpClient創建期間,將其傳給OkHttpClient.Builder,在OkHttpClient中啓用它。沒有定製連接池的情況下,則在OkHttpClient.Builder構造過程中以默認參數
默認情況下,ConnectionPool
最多保存 5個 處於空閒狀態的連接,且連接的默認保活時間爲 5分鐘。也就是默認支持5個併發Socket連接,默認的keepAlive時間爲5分鐘,當然我們可以在構建OkHttpClient時設置不同的值
連接池的緩存操作
ConnectionPool
提供對Deque<RealConnection>
進行操作的方法分別爲put
、get
、connectionBecameIdle
、evictAll
幾個操作。分別對應放入連接、獲取連接、移除連接、移除所有連接操作。
遍歷connections緩存列表,當某個連接計數的次數小於限制的大小以及request的地址和緩存列表中此連接的地址完全匹配。則直接複用緩存列表中的connection作爲request的連接。