主流網(wǎng)絡(luò)層的模式是RxJava+Retrofit+OKHttp,所以我開始研究這三個(gè)項(xiàng)目的源代碼劈猪,淺嘗理解唬渗。
文章的主要內(nèi)容如下:
1.OkHttp簡(jiǎn)介
2.OkHttp使用
3.OkHttp流程源碼跟蹤
一、OKHTTP簡(jiǎn)介
1.支持HTTP2/SPDY
2.socket自動(dòng)選擇最好路線痊远,并支持自動(dòng)重連
3.擁有自動(dòng)維護(hù)的socket連接池苛吱,減少握手次數(shù)
4.擁有隊(duì)列線程池,輕松寫并發(fā)
5.擁有Interceptors輕松處理請(qǐng)求與響應(yīng)(比如透明GZIP壓縮)基于Headers的緩存策略
二阶剑、OKHTTP使用:
1跃巡、GET請(qǐng)求
2危号、POST請(qǐng)求
三、OKHTTP源碼流程分析
(一)素邪、OKHTTP 同步請(qǐng)求debug代碼跟蹤:
從上面代碼所示外莲,先是new了一個(gè)OKHttpClient對(duì)象。
1、OKHttpClient類詳解
OKHttpClient類就比較簡(jiǎn)單了:
- 1偷线、里面包含了很多對(duì)象磨确,其實(shí)OKhttp的很多功能模塊都包裝進(jìn)這個(gè)類,讓這個(gè)類單獨(dú)提供對(duì)外的API声邦,這種外觀模式的設(shè)計(jì)十分的優(yōu)雅乏奥。外觀模式。* 2亥曹、而內(nèi)部模塊比較多邓了,就使用了Builder模式(建造器模式)。Builder模式(建造器模式)* 3媳瞪、它的方法只有一個(gè):newCall.返回一個(gè)Call對(duì)象(一個(gè)準(zhǔn)備好了的可以執(zhí)行和取消的請(qǐng)求)骗炉。
而大家仔細(xì)讀源碼又會(huì)發(fā)現(xiàn)構(gòu)造了OKHttpClient后又new了一個(gè)Rquest對(duì)象。那么咱們就來(lái)看下Request蛇受,說(shuō)道Request又不得不提Response句葵。所以咱們一起講了
2、Request兢仰、Response類詳解
- 1乍丈、Request、Response分別抽象成請(qǐng)求和相應(yīng)* 2旨别、其中Request包括Headers和RequestBody诗赌,而RequestBody是abstract的,他的子類是有FormBody (表單提交的)和 MultipartBody(文件上傳)秸弛,分別對(duì)應(yīng)了兩種不同的MIME類型
FormBody :"application/x-www-form-urlencoded"
MultipartBody:"multipart/"+xxx.* 3铭若、其中Response包括Headers和RequestBody,而ResponseBody是abstract的递览,所以他的子類也是有兩個(gè):RealResponseBody和CacheResponseBody,分別代表真實(shí)響應(yīng)和緩存響應(yīng)叼屠。* 4、由于RFC協(xié)議規(guī)定绞铃,所以所有的頭部信息不是隨便寫的镜雨,request的header與response的header的標(biāo)準(zhǔn)都不同。具體的見(jiàn) List of HTTP header fields儿捧。OKHttp的封裝類Request和Response為了應(yīng)用程序編程方便荚坞,會(huì)把一些常用的Header信息專門提取出來(lái),作為局部變量菲盾。比如contentType颓影,contentLength,code,message,cacheControl,tag...它們其實(shí)都是以name-value對(duì)的形勢(shì)懒鉴,存儲(chǔ)在網(wǎng)絡(luò)請(qǐng)求的頭部信息中诡挂。
根據(jù)從上面的GET請(qǐng)求碎浇,顯示用builder構(gòu)建了Request對(duì)象,然后執(zhí)行了OKHttpClient.java的newCall方法璃俗,那么咱們就看看這個(gè)newCall里面都做什么操作奴璃?
Call是個(gè)什么東西,那咱們看下Call這個(gè)類
Call: HTTP請(qǐng)求任務(wù)封裝
可以說(shuō)我們能用到的操縱基本上都定義在這個(gè)接口里面了城豁,所以也可以說(shuō)這個(gè)類是OKHttp類的核心類了苟穆。我們可以通過(guò)Call對(duì)象來(lái)操作請(qǐng)求了。而Call接口內(nèi)部提供了Factory工廠方法模式(將對(duì)象的創(chuàng)建延遲到工廠類的子類去進(jìn)行唱星,從而實(shí)現(xiàn)動(dòng)態(tài)配置)
Call接口提供了內(nèi)部接口Factory(用于將對(duì)象的創(chuàng)建延遲到該工廠類的子類中進(jìn)行鞭缭,從而實(shí)現(xiàn)動(dòng)態(tài)的配置).
在源碼中,OKHttpClient實(shí)現(xiàn)了Call.Factory接口魏颓,返回了一個(gè)RealCall對(duì)象岭辣。那我們就來(lái)看下RealCall這個(gè)類
4、RealCall類詳解
RealCall
1甸饱、OkHttpClient的newCall方法里面new了RealCall的對(duì)象沦童,但是RealCall的構(gòu)造函數(shù)需要傳入一個(gè)OKHttpClient對(duì)象和Request對(duì)象(PS:第三個(gè)參數(shù)false表示不是webSokcet).因此RealCall包裝了Request對(duì)象。所以RealCall可以很方便地使用這兩個(gè)對(duì)象叹话。
2偷遗、RealCall里面的兩個(gè)關(guān)鍵方法是:execute 和 enqueue。分別用于同步和異步得執(zhí)行網(wǎng)絡(luò)請(qǐng)求驼壶。
3氏豌、RealCall還有一個(gè)重要方法是:getResponseWithInterceptorChain,添加攔截器热凹,通過(guò)攔截器可以將一個(gè)流式工作分解為可配置的分段流程泵喘,既增加了靈活性也實(shí)現(xiàn)了解耦,關(guān)鍵還可以自有配置般妙,非常完美纪铺。
所以client.newCall(request).execute();實(shí)際上執(zhí)行的是RealCall的execute方法,現(xiàn)在咱們?cè)倩貋?lái)看下RealCall的execute的具體實(shí)現(xiàn)
首先是
判斷call是否執(zhí)行過(guò)碟渺,可以看出每個(gè)Call對(duì)象只能使用一次原則鲜锚。然后調(diào)用了captureCallStackTrace()方法。
RealCall.java
RealCall的captureCallStackTrace() 又調(diào)用了Platform.get().getStackTraceForCloseable()
其實(shí)是調(diào)用AndroidPlatform. getStackTraceForCloseable(String closer)方法苫拍。這里就不詳細(xì)說(shuō)了芜繁,后面詳細(xì)說(shuō)。
然后retryAndFollowUpInterceptor.setCallStackTrace(),在這個(gè)方法里面什么都沒(méi)做就是set一個(gè)object進(jìn)去
綜上所示captureCallStackTrace()這個(gè)方法其實(shí)是捕獲了這個(gè)請(qǐng)求的StackTrace绒极。
然后進(jìn)入了第一個(gè)核心類---Dispatcher的的execute方法了骏令,由于下面是進(jìn)入了關(guān)鍵部分,所以重點(diǎn)講解下集峦,代碼如何:
看下OKHttpClient的dispatcher()方法的具體內(nèi)容如下圖
大家發(fā)現(xiàn)client.dispatcher()返回的是Dispatcher對(duì)象伏社,那么這個(gè)Dispatcher對(duì)象是何時(shí)創(chuàng)建的那?在OkHttpClient.java里面Build類里面的構(gòu)造函數(shù)里面塔淤,如下圖
所以默認(rèn)執(zhí)行Builder()放到時(shí)候就創(chuàng)建了一個(gè)Dispatcher摘昌。那么咱們看下dispatcher里面的execute()是如何處理的
里面發(fā)現(xiàn)是runningSyncCalls執(zhí)行了add方法莫非runningSyncCalls是個(gè)list,咱們查看dispatcher里面怎么定義runningSyncCalls的高蜂。
原來(lái)runningSyncCalls是雙向隊(duì)列啊聪黎,突然發(fā)現(xiàn)Dispatcher里面定義了三個(gè)雙向隊(duì)列,看下注釋备恤,我們大概能明白readyAsyncCalls 是一個(gè)存放了等待執(zhí)行任務(wù)Call的雙向隊(duì)列稿饰,runningAsyncCalls是一個(gè)存放異步請(qǐng)求任務(wù)Call的雙向任務(wù)隊(duì)列,runningSyncCalls是一個(gè)存放同步請(qǐng)求的雙向隊(duì)列露泊。關(guān)于隊(duì)列咱們?cè)谙缕恼吕锩嬖敿?xì)介紹喉镰。
執(zhí)行完client.dispatcher().executed(this);要走到getResponseWithInterceptorChain();方法了里面了,看下這個(gè)方法是具體做什么的惭笑?
發(fā)現(xiàn) new了一個(gè)ArrayList侣姆,然后就是不斷的add,后面 new了 RealInterceptorChain對(duì)象沉噩,最后調(diào)用了chain.proceed()方法捺宗。先看下RealInterceptorChain的構(gòu)造函數(shù)。
發(fā)現(xiàn)什么都沒(méi)做就是做了賦值操作川蒙,后面跟蹤下chain.proceed()方法
由于Interceptor是個(gè)接口蚜厉,所以應(yīng)該是具體實(shí)現(xiàn)類RealInterceptorChain的proceed實(shí)現(xiàn)
由于在構(gòu)造RealInterceptorChain對(duì)象時(shí)候httpCodec直接賦予了null,所以下面代碼直接略過(guò)畜眨。
然后看到在proceed方面里面又new了一個(gè)RealInterceptorChain類的next對(duì)象昼牛,溫馨提示下,里面的streamAllocation, httpCodec, connection都是null康聂,所以這個(gè)next對(duì)象和chain最大的區(qū)別就是index屬性值不同chain是0.而next是1匾嘱,然后取interceptors下標(biāo)為1的對(duì)象的interceptor。由從上文可知早抠,如果沒(méi)有開發(fā)者自定義的Interceptor時(shí)霎烙,首先調(diào)用的RetryAndFollowUpInterceptor,如果有開發(fā)者自己定義的interceptor則調(diào)用開發(fā)者interceptor蕊连。
這里重點(diǎn)說(shuō)一下悬垃,由于后面的interceptor比較多,且涉及的也是重要的部分甘苍,而咱們這里主要是講流程尝蠕,所以這里就不詳細(xì)和大家說(shuō)了,由后面再詳細(xì)講解载庭,后面的流程是在每一個(gè)interceptor的intercept方法里面都會(huì)調(diào)用chain.proceed()從而調(diào)用下一個(gè)interceptor的intercept(next)方法看彼,這樣就可以實(shí)現(xiàn)遍歷getResponseWithInterceptorChain里面interceptors的item廊佩,實(shí)現(xiàn)遍歷循環(huán),縮減后的代碼如下:
讀過(guò)源碼我們知道getResponseWithInterceptorChain里面interceptors的最后一個(gè)item是CallServerInterceptor.java靖榕,最后一個(gè)Interceptor(即CallServerInterceptor)里面是直接返回了response 而不是進(jìn)行繼續(xù)遞歸标锄,具體里面是通過(guò)OKio實(shí)現(xiàn)的,具體代碼茁计,等后面再詳細(xì)說(shuō)明料皇,CallServerInterceptor返回response后返回給上一個(gè)interceptor,一般是開發(fā)者自己定義的networkInterceptor,然后開發(fā)者自己的networkInterceptor把他的response返回給前一個(gè)interceptor星压,依次以此類推返回給第一個(gè)interceptor践剂,這時(shí)候又回到了realCall里面的execute()里面了,代碼如下:
(二)娜膘、OKHTTP 異步請(qǐng)求debug代碼跟蹤:
前面和同步一樣new了一個(gè)OKHttp和Request逊脯。這塊和同步一樣就不說(shuō)了,那么說(shuō)說(shuō)和同步不一樣的地方竣贪,后面異步進(jìn)入enqueue()方法
由于executed默認(rèn)為false男窟,所以先進(jìn)行判斷是否為true,為true則直接跑異常贾富,沒(méi)有則設(shè)置為true歉眷,可以看出executed這個(gè)是一個(gè)標(biāo)志,標(biāo)志這個(gè)請(qǐng)求是否已經(jīng)正在請(qǐng)求中颤枪,合同步一樣先調(diào)用了captureCallStackTrace();然后調(diào)用 client.dispatcher().enqueue(new AsyncCall(responseCallback));client.dispatcher()返回的是Dispatcher對(duì)象所以實(shí)際調(diào)用的是Dispatcher的enqueue(),那么咱們進(jìn)入源碼看下
根據(jù)源碼和注釋大家可以看到如果正在執(zhí)行的異步請(qǐng)求小于64汗捡,并且請(qǐng)求同一個(gè)主機(jī)小于5的時(shí)候就先往正在運(yùn)行的隊(duì)列里面添加這個(gè)call,然后用線程池去執(zhí)行這個(gè)call,否則就把他放到等待隊(duì)列里面畏纲。執(zhí)行這個(gè)call的時(shí)候扇住,自然會(huì)去走到這個(gè)call的run方法,那么咱們看下AsyncCall.java這個(gè)類,而AsyncCall.java又繼承自NamedRunnable.java咱們就一起看下他們的源碼
上面看到NamedRunnable的構(gòu)造方法設(shè)置了name在的run方法里面設(shè)定為當(dāng)前線程的name,而NamedRunnable的run方法里面調(diào)用了它自己的抽象方法execute盗胀,由此可見(jiàn)NamedRunnable的作用就是設(shè)置了線程的name艘蹋,然后回調(diào)子類的execute方法,那么我們來(lái)看下AsyncCall的execute方法票灰。貌似好像又回到了之前同步的getResponseWithInterceptorChain()里面女阀,根據(jù)返回的response來(lái)這只callback回調(diào)。所以我們得到了OKHTTP的大體流程屑迂,如下圖:
三浸策、OKHTTP類詳解
整體的流程圖