主流網(wǎng)絡層的模式是RxJava+Retrofit+OKHttp,所以我開始研究這三個項目的源代碼,淺嘗理解。
文章的主要內(nèi)容如下:
1.OkHttp簡介
2.OkHttp使用
3.OkHttp流程源碼跟蹤
一、OKHTTP簡介
1.支持HTTP2/SPDY
2.socket自動選擇最好路線,并支持自動重連
3.擁有自動維護的socket連接池,減少握手次數(shù)
4.擁有隊列線程池,輕松寫并發(fā)
5.擁有Interceptors輕松處理請求與響應(比如透明GZIP壓縮)基于Headers的緩存策略
二、OKHTTP使用:
1、GET請求

2、POST請求

三、OKHTTP源碼流程分析
(一)、OKHTTP 同步請求debug代碼跟蹤:

從上面代碼所示,先是new了一個OKHttpClient對象。
1、OKHttpClient類詳解
OKHttpClient類就比較簡單了:
- 1、里面包含了很多對象,其實OKhttp的很多功能模塊都包裝進這個類,讓這個類單獨提供對外的API,這種外觀模式的設(shè)計十分的優(yōu)雅。外觀模式。* 2、而內(nèi)部模塊比較多,就使用了Builder模式(建造器模式)。Builder模式(建造器模式)* 3、它的方法只有一個:newCall.返回一個Call對象(一個準備好了的可以執(zhí)行和取消的請求)。
而大家仔細讀源碼又會發(fā)現(xiàn)構(gòu)造了OKHttpClient后又new了一個Rquest對象。那么咱們就來看下Request,說道Request又不得不提Response。所以咱們一起講了
2、Request、Response類詳解
- 1、Request、Response分別抽象成請求和相應* 2、其中Request包括Headers和RequestBody,而RequestBody是abstract的,他的子類是有FormBody (表單提交的)和 MultipartBody(文件上傳),分別對應了兩種不同的MIME類型
FormBody :"application/x-www-form-urlencoded"
MultipartBody:"multipart/"+xxx.* 3、其中Response包括Headers和RequestBody,而ResponseBody是abstract的,所以他的子類也是有兩個:RealResponseBody和CacheResponseBody,分別代表真實響應和緩存響應。* 4、由于RFC協(xié)議規(guī)定,所以所有的頭部信息不是隨便寫的,request的header與response的header的標準都不同。具體的見 List of HTTP header fields。OKHttp的封裝類Request和Response為了應用程序編程方便,會把一些常用的Header信息專門提取出來,作為局部變量。比如contentType,contentLength,code,message,cacheControl,tag...它們其實都是以name-value對的形勢,存儲在網(wǎng)絡請求的頭部信息中。
根據(jù)從上面的GET請求,顯示用builder構(gòu)建了Request對象,然后執(zhí)行了OKHttpClient.java的newCall方法,那么咱們就看看這個newCall里面都做什么操作?

Call是個什么東西,那咱們看下Call這個類
Call: HTTP請求任務封裝
可以說我們能用到的操縱基本上都定義在這個接口里面了,所以也可以說這個類是OKHttp類的核心類了。我們可以通過Call對象來操作請求了。而Call接口內(nèi)部提供了Factory工廠方法模式(將對象的創(chuàng)建延遲到工廠類的子類去進行,從而實現(xiàn)動態(tài)配置)
Call接口提供了內(nèi)部接口Factory(用于將對象的創(chuàng)建延遲到該工廠類的子類中進行,從而實現(xiàn)動態(tài)的配置).

在源碼中,OKHttpClient實現(xiàn)了Call.Factory接口,返回了一個RealCall對象。那我們就來看下RealCall這個類
4、RealCall類詳解
RealCall
1、OkHttpClient的newCall方法里面new了RealCall的對象,但是RealCall的構(gòu)造函數(shù)需要傳入一個OKHttpClient對象和Request對象(PS:第三個參數(shù)false表示不是webSokcet).因此RealCall包裝了Request對象。所以RealCall可以很方便地使用這兩個對象。
2、RealCall里面的兩個關(guān)鍵方法是:execute 和 enqueue。分別用于同步和異步得執(zhí)行網(wǎng)絡請求。
3、RealCall還有一個重要方法是:getResponseWithInterceptorChain,添加攔截器,通過攔截器可以將一個流式工作分解為可配置的分段流程,既增加了靈活性也實現(xiàn)了解耦,關(guān)鍵還可以自有配置,非常完美。
所以client.newCall(request).execute();實際上執(zhí)行的是RealCall的execute方法,現(xiàn)在咱們再回來看下RealCall的execute的具體實現(xiàn)

首先是

判斷call是否執(zhí)行過,可以看出每個Call對象只能使用一次原則。然后調(diào)用了captureCallStackTrace()方法。
RealCall.java

RealCall的captureCallStackTrace() 又調(diào)用了Platform.get().getStackTraceForCloseable()

其實是調(diào)用AndroidPlatform. getStackTraceForCloseable(String closer)方法。這里就不詳細說了,后面詳細說。
然后retryAndFollowUpInterceptor.setCallStackTrace(),在這個方法里面什么都沒做就是set一個object進去

綜上所示captureCallStackTrace()這個方法其實是捕獲了這個請求的StackTrace。
然后進入了第一個核心類---Dispatcher的的execute方法了,由于下面是進入了關(guān)鍵部分,所以重點講解下,代碼如何:

看下OKHttpClient的dispatcher()方法的具體內(nèi)容如下圖

大家發(fā)現(xiàn)client.dispatcher()返回的是Dispatcher對象,那么這個Dispatcher對象是何時創(chuàng)建的那?在OkHttpClient.java里面Build類里面的構(gòu)造函數(shù)里面,如下圖

所以默認執(zhí)行Builder()放到時候就創(chuàng)建了一個Dispatcher。那么咱們看下dispatcher里面的execute()是如何處理的

里面發(fā)現(xiàn)是runningSyncCalls執(zhí)行了add方法莫非runningSyncCalls是個list,咱們查看dispatcher里面怎么定義runningSyncCalls的。

原來runningSyncCalls是雙向隊列啊,突然發(fā)現(xiàn)Dispatcher里面定義了三個雙向隊列,看下注釋,我們大概能明白readyAsyncCalls 是一個存放了等待執(zhí)行任務Call的雙向隊列,runningAsyncCalls是一個存放異步請求任務Call的雙向任務隊列,runningSyncCalls是一個存放同步請求的雙向隊列。關(guān)于隊列咱們在下篇文章里面詳細介紹。
執(zhí)行完client.dispatcher().executed(this);要走到getResponseWithInterceptorChain();方法了里面了,看下這個方法是具體做什么的?

發(fā)現(xiàn) new了一個ArrayList,然后就是不斷的add,后面 new了 RealInterceptorChain對象,最后調(diào)用了chain.proceed()方法。先看下RealInterceptorChain的構(gòu)造函數(shù)。

發(fā)現(xiàn)什么都沒做就是做了賦值操作,后面跟蹤下chain.proceed()方法
由于Interceptor是個接口,所以應該是具體實現(xiàn)類RealInterceptorChain的proceed實現(xiàn)


由于在構(gòu)造RealInterceptorChain對象時候httpCodec直接賦予了null,所以下面代碼直接略過。

然后看到在proceed方面里面又new了一個RealInterceptorChain類的next對象,溫馨提示下,里面的streamAllocation, httpCodec, connection都是null,所以這個next對象和chain最大的區(qū)別就是index屬性值不同chain是0.而next是1,然后取interceptors下標為1的對象的interceptor。由從上文可知,如果沒有開發(fā)者自定義的Interceptor時,首先調(diào)用的RetryAndFollowUpInterceptor,如果有開發(fā)者自己定義的interceptor則調(diào)用開發(fā)者interceptor。
這里重點說一下,由于后面的interceptor比較多,且涉及的也是重要的部分,而咱們這里主要是講流程,所以這里就不詳細和大家說了,由后面再詳細講解,后面的流程是在每一個interceptor的intercept方法里面都會調(diào)用chain.proceed()從而調(diào)用下一個interceptor的intercept(next)方法,這樣就可以實現(xiàn)遍歷getResponseWithInterceptorChain里面interceptors的item,實現(xiàn)遍歷循環(huán),縮減后的代碼如下:




讀過源碼我們知道getResponseWithInterceptorChain里面interceptors的最后一個item是CallServerInterceptor.java,最后一個Interceptor(即CallServerInterceptor)里面是直接返回了response 而不是進行繼續(xù)遞歸,具體里面是通過OKio實現(xiàn)的,具體代碼,等后面再詳細說明,CallServerInterceptor返回response后返回給上一個interceptor,一般是開發(fā)者自己定義的networkInterceptor,然后開發(fā)者自己的networkInterceptor把他的response返回給前一個interceptor,依次以此類推返回給第一個interceptor,這時候又回到了realCall里面的execute()里面了,代碼如下:

(二)、OKHTTP 異步請求debug代碼跟蹤:

前面和同步一樣new了一個OKHttp和Request。這塊和同步一樣就不說了,那么說說和同步不一樣的地方,后面異步進入enqueue()方法

由于executed默認為false,所以先進行判斷是否為true,為true則直接跑異常,沒有則設(shè)置為true,可以看出executed這個是一個標志,標志這個請求是否已經(jīng)正在請求中,合同步一樣先調(diào)用了captureCallStackTrace();然后調(diào)用 client.dispatcher().enqueue(new AsyncCall(responseCallback));client.dispatcher()返回的是Dispatcher對象所以實際調(diào)用的是Dispatcher的enqueue(),那么咱們進入源碼看下

根據(jù)源碼和注釋大家可以看到如果正在執(zhí)行的異步請求小于64,并且請求同一個主機小于5的時候就先往正在運行的隊列里面添加這個call,然后用線程池去執(zhí)行這個call,否則就把他放到等待隊列里面。執(zhí)行這個call的時候,自然會去走到這個call的run方法,那么咱們看下AsyncCall.java這個類,而AsyncCall.java又繼承自NamedRunnable.java咱們就一起看下他們的源碼


上面看到NamedRunnable的構(gòu)造方法設(shè)置了name在的run方法里面設(shè)定為當前線程的name,而NamedRunnable的run方法里面調(diào)用了它自己的抽象方法execute,由此可見NamedRunnable的作用就是設(shè)置了線程的name,然后回調(diào)子類的execute方法,那么我們來看下AsyncCall的execute方法。貌似好像又回到了之前同步的getResponseWithInterceptorChain()里面,根據(jù)返回的response來這只callback回調(diào)。所以我們得到了OKHTTP的大體流程,如下圖:
三、OKHTTP類詳解
整體的流程圖
