OkHttp 3.7原始碼分析(一)——整體架構
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提供了兩種呼叫方式:
- 同步呼叫
- 非同步呼叫
同步呼叫
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain(false);
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
首先加鎖置標誌位,接著使用分配器的executed方法將call加入到同步佇列中,然後呼叫getResponseWithInterceptorChain方法(稍後分析)執行http請求,最後呼叫finishied方法將call從同步佇列中刪除
非同步請求
void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
同樣先置標誌位,然後將封裝的一個執行體放到非同步執行佇列中。這裡面引入了一個新的類AsyncCall,這個類繼承於NamedRunnable,實現了Runnable介面。NamedRunnable可以給當前的執行緒設定名字,並且用模板方法將執行緒的執行體放到了execute方法中
攔截器
除了同步呼叫和非同步呼叫,OkHttp還提供了一個攔截器的概念。攔截器提供了攔截請求和攔截伺服器應答的介面。OkHttp提供了一個攔截器鏈的概念,通過將一個個攔截器組合成一個攔截器鏈,可以達到在不同層面做不同攔截操作的效果,有點AOP的意思。具體攔截器的使用可以參考:Okhttp-wiki 之 Interceptors 攔截器
總體架構
上圖是OkHttp的總體架構,大致可以分為以下幾層:
- Interface——介面層:接受網路訪問請求
- Protocol——協議層:處理協議邏輯
- Connection——連線層:管理網路連線,傳送新的請求,接收伺服器訪問
- Cache——快取層:管理本地快取
- I/O——I/O層:實際資料讀寫實現
- Inteceptor——攔截器層:攔截網路訪問,插入攔截邏輯
Interface——介面層:
介面層接收使用者的網路訪問請求(同步請求/非同步請求),發起實際的網路訪問。OkHttpClient
是OkHttp框架的客戶端,更確切的說是一個使用者皮膚。使用者使用OkHttp進行各種設定,發起各種網路請求都是通過OkHttpClient
完成的。每個OkHttpClient
內部都維護了屬於自己的任務佇列,連線池,Cache,攔截器等,所以在使用OkHttp作為網路框架時應該全域性共享一個OkHttpClient
例項。
Call
描述一個實際的訪問請求,使用者的每一個網路請求都是一個Call
例項。Call
本身只是一個介面,定義了Call
的介面方法,實際執行過程中,OkHttp會為每一個請求建立一個RealCall
,每一個RealCall
內部有一個AsyncCall
:
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@Override protected void execute() {
...
}
...
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
AsyncCall
繼承的NamedRunnable
繼承自Runnable介面:
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
所以每一個Call就是一個執行緒,而執行Call的過程就是執行其execute
方法的過程。
Dispatcher
是OkHttp的任務佇列,其內部維護了一個執行緒池,當有接收到一個Call
時,Dispatcher
負責線上程池中找到空閒的執行緒並執行其execute
方法。這部分將會單獨拿一篇部落格進行介紹,詳細內容可參考本系列接下來的文章。
Protocol——協議層:處理協議邏輯
Protocol層負責處理協議邏輯,OkHttp支援Http1/Http2/WebSocket協議,並在3.7版本中放棄了對Spdy協議,鼓勵開發者使用Http/2。
Connection——連線層:管理網路連線,傳送新的請求,接收伺服器訪問
連線層顧名思義就是負責網路連線。在連線層中有一個連線池,統一管理所有的Socket連線,當使用者新發起一個網路請求時,OkHttp會首先從連線池中查詢是否有符合要求的連線,如果有則直接通過該連線傳送網路請求;否則新建立一個網路連線。
RealConnection
描述一個物理Socket連線,連線池中維護多個RealConnection例項。由於Http/2支援多路複用,一個RealConnection
可以支援多個網路訪問請求,所以OkHttp又引入了StreamAllocation
來描述一個實際的網路請求開銷(從邏輯上一個Stream
對應一個Call
,但在實際網路請求過程中一個Call
常常涉及到多次請求。如重定向,Authenticate等場景。所以準確地說,一個Stream
對應一次請求,而一個Call
對應一組有邏輯關聯的Stream
),一個RealConnection
對應一個或多個StreamAllocation
,所以StreamAllocation
可以看做是RealConenction
的計數器,當RealConnection
的引用計數變為0,且長時間沒有被其他請求重新佔用就將被釋放。
連線層是OkHttp的核心部分,這部分當然也會單獨拿一篇部落格詳細講解,詳細內容可參考本專題相關文章。
Cache——快取層:管理本地快取
Cache層負責維護請求快取,當使用者的網路請求在本地已有符合要求的快取時,OkHttp會直接從快取中返回結果,從而節省網路開銷。這部分內容也會單獨拿一篇部落格進行介紹,詳細內容可參考本專題相關文章。
I/O——I/O層:實際資料讀寫實現
I/O層負責實際的資料讀寫。OkHttp的另一大有點就是其高效的I/O操作,這歸因於其高效的I/O庫okio
這部分內容筆者也打算另開一個專題進行介紹。詳細內容可以參考本部落格相關內容。
Inteceptor——攔截器層:攔截網路訪問,插入攔截邏輯
攔截器層提供了一個類AOP介面,方便使用者可以切入到各個層面對網路訪問進行攔截並執行相關邏輯。在下一篇部落格中,筆者將通過介紹一個實際的網路訪問請求例項來介紹攔截器的原理。
轉自:http://blog.csdn.net/asialiyazhou/article/details/72598320
相關文章
- 原始碼分析三:OkHttp(1)—總體架構原始碼HTTP架構
- jQuery原始碼分析系列 : 整體架構jQuery原始碼架構
- OkHttp 3.7原始碼分析(四)——快取策略HTTP原始碼快取
- OkHttp 3.7原始碼分析(五)——連線池HTTP原始碼
- 精盡 MyBatis 原始碼分析 - 整體架構MyBatis原始碼架構
- OkHttp 3.7原始碼分析(三)——任務佇列HTTP原始碼佇列
- OkHttp3.7原始碼分析(四)——快取策略HTTP原始碼快取
- OkHttp3.7原始碼分析(三)——任務佇列HTTP原始碼佇列
- jQuery整體架構原始碼解析jQuery架構原始碼
- OkHttp 原始碼剖析系列(二)——攔截器整體流程分析HTTP原始碼
- MyBatis原始碼窺探(一):MyBatis整體架構解析MyBatis原始碼架構
- tomcat原始碼分析(第一篇 從整體架構開始)Tomcat原始碼架構
- 【Mybatis原始碼解析】- 整體架構及原理MyBatis原始碼架構
- OkHttp原始碼分析HTTP原始碼
- Mybatis原始碼分析-整體設計(一)MyBatis原始碼
- 微信MMKV原始碼分析(一) | 整體流程原始碼
- OkHttp 原始碼分析(一)—— 請求流程HTTP原始碼
- 【深入淺出jQuery】原始碼淺析–整體架構jQuery原始碼架構
- OkHttp 3.7原始碼分析(二)——攔截器&一個實際網路請求的實現HTTP原始碼
- Android OkHttp3原始碼詳解——整體框架AndroidHTTP原始碼框架
- 大家都能看得懂的原始碼(一)ahooks 整體架構篇原始碼Hook架構
- OkHttp3.0-原始碼分析HTTP原始碼
- 原始碼分析三:OkHttp—CacheInterceptor原始碼HTTP
- 原始碼分析三:OkHttp—CallServerInterceptor原始碼HTTPServer
- 原始碼分析三:OkHttp—RetryAndFollowUpInterceptor原始碼HTTP
- 原始碼分析筆記——OkHttp原始碼筆記HTTP
- ==[圖]Spark系列(四)整體架構分析Spark架構
- 【OkHttp3原始碼分析】(一)Request的executeHTTP原始碼
- Okhttp同步請求原始碼分析HTTP原始碼
- 原始碼分析三:OkHttp—BridgeInterceptor原始碼HTTP
- 原始碼分析三:OkHttp—ConnectInterceptor原始碼HTTP
- OkHttp3原始碼分析[DiskLruCache]HTTP原始碼
- RPC框架整體架構設計分析RPC框架架構
- 深入OKHttp原始碼分析(一)----同步和非同步請求流程和原始碼分析HTTP原始碼非同步
- MongoDB原始碼分析之Command體系架構CJMongoDB原始碼架構
- Docker整體架構Docker架構
- nginx 整體架構Nginx架構
- DM 原始碼閱讀系列文章(二)整體架構介紹原始碼架構