天天看點

OkHttp 3.7源碼分析(一)——整體架構

okhttp3.7源碼分析文章清單如下:

<a href="https://yq.aliyun.com/articles/78105?spm=5176.8091938.0.0.hleond">okhttp源碼分析——整體架構</a>

<a href="https://yq.aliyun.com/articles/78104?spm=5176.8091938.0.0.hleond">okhttp源碼分析——攔截器</a>

<a href="https://yq.aliyun.com/articles/78103?spm=5176.8091938.0.0.hleond">okhttp源碼分析——任務隊列</a>

<a href="https://yq.aliyun.com/articles/78102?spm=5176.8091938.0.0.hleond">okhttp源碼分析——緩存政策</a>

<a href="https://yq.aliyun.com/articles/78101?spm=5176.8091938.0.0.hleond">okhttp源碼分析——多路複用</a>

okhttp是一個處理網絡請求的開源項目,是android端最火熱的輕量級架構,由移動支付square公司貢獻用于替代httpurlconnection和apache httpclient。随着okhttp的不斷成熟,越來越多的android開發者使用okhttp作為網絡架構。

之是以可以赢得如此多開發者的喜愛,主要得益于如下特點:

支援https/http2/websocket(在okhttp3.7中已經剝離對spdy的支援,轉而大力支援http2)

内部維護任務隊列線程池,友好支援并發通路

内部維護連接配接池,支援多路複用,減少連接配接建立開銷

socket建立支援最佳路由

提供攔截器鍊(interceptorchain),實作request與response的分層處理(如透明gzip壓縮,logging等)

為了一探okhttp是如何具備以下特點的,筆者反複研究okhttp架構源碼,力求通過源碼分析向各位解釋一二。是以特意準備了幾篇部落格跟大家一起探讨下okhttp的方方面面,今天首先從整體架構上分析下okhttp。

首先來看下okhttp的簡單使用,okhttp提供了兩種調用方式:

同步調用

異步調用

首先加鎖置标志位,接着使用配置設定器的executed方法将call加入到同步隊列中,然後調用getresponsewithinterceptorchain方法(稍後分析)執行http請求,最後調用finishied方法将call從同步隊列中删除

同樣先置标志位,然後将封裝的一個執行體放到異步執行隊列中。這裡面引入了一個新的類asynccall,這個類繼承于namedrunnable,實作了runnable接口。namedrunnable可以給目前的線程設定名字,并且用模闆方法将線程的執行體放到了execute方法中

OkHttp 3.7源碼分析(一)——整體架構

上圖是okhttp的總體架構,大緻可以分為以下幾層:

interface——接口層:接受網絡通路請求

protocol——協定層:處理協定邏輯

connection——連接配接層:管理網絡連接配接,發送新的請求,接收伺服器通路

cache——緩存層:管理本地緩存

i/o——i/o層:實際資料讀寫實作

inteceptor——攔截器層:攔截網絡通路,插入攔截邏輯

接口層接收使用者的網絡通路請求(同步請求/異步請求),發起實際的網絡通路。<code>okhttpclient</code>是okhttp架構的用戶端,更确切的說是一個使用者面闆。使用者使用okhttp進行各種設定,發起各種網絡請求都是通過<code>okhttpclient</code>完成的。每個<code>okhttpclient</code>内部都維護了屬于自己的任務隊列,連接配接池,cache,攔截器等,是以在使用okhttp作為網絡架構時應該全局共享一個<code>okhttpclient</code>執行個體。

<code>call</code>描述一個實際的通路請求,使用者的每一個網絡請求都是一個<code>call</code>執行個體。<code>call</code>本身隻是一個接口,定義了<code>call</code>的接口方法,實際執行過程中,okhttp會為每一個請求建立一個<code>realcall</code>,每一個<code>realcall</code>内部有一個<code>asynccall</code>:

<code>asynccall</code>繼承的<code>namedrunnable</code>繼承自runnable接口:

是以每一個call就是一個線程,而執行call的過程就是執行其<code>execute</code>方法的過程。

<code>dispatcher</code>是okhttp的任務隊列,其内部維護了一個線程池,當有接收到一個<code>call</code>時,<code>dispatcher</code>負責線上程池中找到空閑的線程并執行其<code>execute</code>方法。這部分将會單獨拿一篇部落格進行介紹,詳細内容可參考本系列接下來的文章。

protocol層負責處理協定邏輯,okhttp支援http1/http2/websocket協定,并在3.7版本中放棄了對spdy協定,鼓勵開發者使用http/2。

連接配接層顧名思義就是負責網絡連接配接。在連接配接層中有一個連接配接池,統一管理所有的socket連接配接,當使用者新發起一個網絡請求時,okhttp會首先從連接配接池中查找是否有符合要求的連接配接,如果有則直接通過該連接配接發送網絡請求;否則新建立一個網絡連接配接。

<code>realconnection</code>描述一個實體socket連接配接,連接配接池中維護多個realconnection執行個體。由于http/2支援多路複用,一個<code>realconnection</code>可以支援多個網絡通路請求,是以okhttp又引入了<code>streamallocation</code>來描述一個實際的網絡請求開銷(從邏輯上一個<code>stream</code>對應一個<code>call</code>,但在實際網絡請求過程中一個<code>call</code>常常涉及到多次請求。如重定向,authenticate等場景。是以準确地說,一個<code>stream</code>對應一次請求,而一個<code>call</code>對應一組有邏輯關聯的<code>stream</code>),一個<code>realconnection</code>對應一個或多個<code>streamallocation</code>,是以<code>streamallocation</code>可以看做是<code>realconenction</code>的計數器,當<code>realconnection</code>的引用計數變為0,且長時間沒有被其他請求重新占用就将被釋放。

連接配接層是okhttp的核心部分,這部分當然也會單獨拿一篇部落格詳細講解,詳細内容可參考本專題相關文章。

cache層負責維護請求緩存,當使用者的網絡請求在本地已有符合要求的緩存時,okhttp會直接從緩存中傳回結果,進而節省網絡開銷。這部分内容也會單獨拿一篇部落格進行介紹,詳細内容可參考本專題相關文章。

這部分内容筆者也打算另開一個專題進行介紹。詳細内容可以參考本部落格相關内容。

攔截器層提供了一個類aop接口,友善使用者可以切入到各個層面對網絡通路進行攔截并執行相關邏輯。在下一篇部落格中,筆者将通過介紹一個實際的網絡通路請求執行個體來介紹攔截器的原理。