OkHttp3 架構分析
我們都知道在OkHttp3中,其靈活性,很大程度上體現在,我們可以 intercept 其任意一個環節,而這個優勢便是okhttp3整個請求響應架構體系的精髓所在:
- 在OkHttp3中,每一個請求任務都封裝為一個 Call ,其實現為 RealCall 。
- 而所有的策略幾乎都可以通過 OkHttpClient 傳入
- 所有全局策略與數據,除了存儲在允許上層訪問的 OkHttpClient 實例以外,還有一部分是存儲在只允許包可見的 Internal.instance 中(如連接池、路由黑名單等)
- OkHttp中用戶可傳入的 interceptor 分為兩類,一類是全局 interceptor ,該類 interceptor 在請求開始之前最早被調用,另外一類為非網頁請求的 networkInterceptor ,這類 interceptor 只有在非網頁請求中會被調用,并且是在組裝完成請求之后,真正發起請求之前被調用(這塊具體可以參看 RealCall#getResponseWithInterceptorChain() 方法)
- 整個請求過程通過遞歸 RealInterceptorChain#proceed 來實現,在每個 interceptor 中調用遞歸到下一個 interceptor 來完成整個請求流程,并且在遞歸回到當前 interceptor 后完成響應處理
- 在異步請求中,我們通過 Callback 來獲得簡單清晰的請求回調( onFailure 、 onResponse )
- 但是在 OkHttpClient 中,我們可以傳入 EventListener 的工廠方法,為每一個請求創建一個 EventListener ,來接收非常細的事件回調
連接池
我們知道在OkHttp3存在連接池,并且該連接池是通過與 StreamAllocation 的配合完成連接池的維護。
- 所有的請求連接都會通過 StreamAllocation 進行獲得,并且結合 ConnectionPool 進行引用計數,來有效緩存連接
- 而在 StreamAllocation 中,通過 RouteSelector 來根據請求地址進行路由處理,期間就涉及到了 DNS解析 、 協議處理 、 代理選擇 、 簽名校驗 等
默認連接池策略:
- 最多64個請求
- 同一個host最多5個請求
- 連接最長閑置5分鐘
- 異步連接所在線程池名: OkHttp Dispatcher
- 常駐清理連接線程池: OkHttp ConnectionPool
獲得連接
連接池
II. 各類線程池分析
OkHttp中的對所有的任務采用 NamedRunnable ,與我開源的 ThreadDebugger 中通過架構層面約束,讓每個執行單元給出對應的業務名稱,以便于線程維護不謀而合。關于Android中 ThreadPoolExecutor 的機制,可以看我之前寫的這篇文章。
1. 異步請求線程池
該線程池名 OkHttp Dispatcher ,該線程用于執行異步的請求任務。
- 該線程池本身: 無任務上限,自動回收閑置60s的線程
- 但是 Dispatcher 中在進口進行把關控制,默認情況下保證在當前進程中 OkHttpClient 最多只有64個請求,池子中相同host的請求不超過5個
- 架構上通過兩個雙端隊列( readyAsyncCalls:Deque<AsyncCall> 與 runningAsyncCals:Dequeue<AsyncCall> )分別用于維護等待中的任務與運行中的任務
- 在每一個異步任務后,都會檢查一遍 readyAsyncCalls ,在滿足條件下,將最先進入隊列的任務丟入該線程池進行執行
2. 連接池清理線程池
該線程池名 OkHttp ConnectionPool ,該線程用于自動清理長時間閑置或泄漏的連接。
- 該線程本身: 無任務上限,自動回收閑置60s的線程
- 但是 ConnectionPool 中通過一個 cleanupRunning 的標記,控制當前僅有一個清理任務進入隊列
- 清理任務,會不斷清理,在所有需要清理的連接都清理完成后,會計算出最近一次需要清理的時間并阻塞,不斷清理直到連接池中沒有任何連接,方才結束
- 在每次有連接加入連接池時,如果當前沒有清理任務運行,會加入一個清理任務到清理線程池中執行
3. 緩存整理線程池
該線程池名 OkHttp DiskLruCache ,該線程池用于整理本地請求結果的緩存。
- 該線程池本身: 最多1個運行中線程,其余任務會阻塞住等待,回收閑置60s的線程
- 由于可運行僅為一個線程,因此所有操作無需考慮線程安全問題
- 緩存的整理包含: 達到閥值大小的文件,刪除最近最少使用的記錄;在有關操作達到一定數量以后對記錄進行重建
4. HTTP2異步事務線程池
該線程池名 OkHttp Http2Connection ,我們都知道HTTP2采用了多路復用(相關知識可以翻看這篇文章),因此需要維護連接有效性,本線程池就是用于維護相關的各類HTTP2事務
- 該線程池本身: 無任務上限,自動回收閑置60s的線程
- 每一個HTTP2連接都有這么一個線程池存在
回望 FileDownloader ,有一個極大的痛點是,在最早其就引入了多進程,雖然在后期實現了單進程與多進程的切換,但是整套體系不得不為該多進程買單,極大的增加了相關的復雜度,以及無法輕量的同步回調。如果讓我再寫一個下載引擎,我也許也會考慮分拆各個模塊,讓核心代碼保持充分的簡單,也讓每個模塊足夠單一。
來自:https://blog.dreamtobe.cn/okhttp3-framework/