一:先看看okhttp簡(jiǎn)單的配置以及使用:
1. 在app的module中先配置依賴 ?implementation'com.squareup.okhttp3:okhttp:3.10.0'
2.okhttp執(zhí)行網(wǎng)絡(luò)請(qǐng)求調(diào)用方式:
????異步請(qǐng)求調(diào)用Call.enqueue()早抠;同步請(qǐng)求調(diào)用Call.execute()
二:框架基本流程源碼剖析
由于OkhttpClient內(nèi)部有非常復(fù)雜且多的參數(shù)配置憋活,作為一個(gè)框架來(lái)說(shuō)驾讲,為了讓用戶使用起來(lái)比較友好秸妥,采用了建造者模式逗载,來(lái)構(gòu)建OkhttpClient所需要的一些重要的參數(shù)配置項(xiàng),這里就不用多說(shuō)了。
然后我們先分析下一步代碼Call call = okHttpClient.newCall(request);這里通過(guò)newCall得到了一個(gè)Call對(duì)象睡腿,根據(jù)代碼調(diào)用鏈可以看出,newCall實(shí)際創(chuàng)建的是一個(gè)名叫RealCall的對(duì)象峻贮。????????
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public CallnewCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
static RealCallnewRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
? RealCall call =new RealCall(client, originalRequest, forWebSocket);
? call.eventListener = client.eventListenerFactory().create(call);
? return call;
}
然后我們繼續(xù)跟進(jìn)席怪,先看下enqueue這個(gè)異步請(qǐng)求究竟是怎么處理的
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed)throw new IllegalStateException("Already Executed");
? ? executed =true;
? }
captureCallStackTrace();
? eventListener.callStart(this);
? client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
這里我們可以看到,他在這里做了個(gè)判斷纤控,如果同一個(gè)Call對(duì)象調(diào)用了多次enqueue挂捻,這里回拋出異常。接下來(lái)看關(guān)鍵代碼船万,最終okhttp框架將Callback(也就是我們請(qǐng)求的時(shí)候傳進(jìn)來(lái)的回調(diào)函數(shù))包裝為了一個(gè)AysncCall(這個(gè)AysncCall實(shí)際是一個(gè)Runnable细层,最終由Dispatcher類中維護(hù)的線程池中的線程執(zhí)行)惜辑,交給了一個(gè)叫做Dispatcher的類,我們繼續(xù)跟進(jìn)...
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() <?maxRequests?&&?runningCallsForHost(call) <?maxRequestsPerHost){
runningAsyncCalls.add(call);
? ? executorService().execute(call);
? }else {
readyAsyncCalls.add(call);
? }
}
這里可以看到Dispatcher類里面維護(hù)了三個(gè)隊(duì)列疫赎,包含運(yùn)行中的異步請(qǐng)求隊(duì)列runningAysncCalls,運(yùn)行中的同步請(qǐng)求隊(duì)列runningSyncCalls碎节,以及待運(yùn)行的異步請(qǐng)求隊(duì)列readyAsyncCalls捧搞。在調(diào)用enqueue的時(shí)候,框架層先判斷正在運(yùn)行中的異步隊(duì)列runningAysncCalls的個(gè)數(shù)是否小于最大請(qǐng)求數(shù)maxRequests(默認(rèn)64)狮荔,并且判斷這個(gè)即將添加的請(qǐng)求的host在runningAysncCalls中是否小于maxRequestsPerHost(默認(rèn)5)胎撇,都滿足則將這個(gè)封裝由請(qǐng)求信息的Call對(duì)象添加到runningAysncCalls,并且交給線程池executorService執(zhí)行殖氏,不滿足則添加到準(zhǔn)備隊(duì)列readyAsyncCalls晚树。剛才已經(jīng)說(shuō)過(guò)了AsyncCall是一個(gè)Runnable,也就是最終由線程執(zhí)行到AsyncCall的execute方法雅采,繼續(xù)...
這里可以看到execute方法最終是通過(guò)getResponseWithInterceptorChain()得到Response爵憎,然后通過(guò)我們?cè)趀nqueue時(shí)傳進(jìn)來(lái)的那個(gè)Callback將結(jié)果回調(diào)出去。追蹤同步請(qǐng)求代碼調(diào)用鏈也發(fā)現(xiàn)婚瓜,最終也是這個(gè)方法返回得到Response宝鼓,那么接下來(lái)看看getResponseWithInterceptorChain
從getResponseWithInterceptorChain這個(gè)方法,框架是將一些Interceptor添加到一個(gè)list中巴刻,然后創(chuàng)建了一個(gè)RealInterceptorChain愚铡,調(diào)用了它的proceed方法
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
? ? RealConnection connection)throws IOException {
//************省略代碼
// 這里又創(chuàng)建了一個(gè)RealInterceptorChain,不過(guò)這里有個(gè)關(guān)鍵參數(shù)不一樣胡陪,那就是index +1沥寥,這里邏輯是先處理攔截器集合的Interceptor的intercept方法,處理每個(gè)攔截器自己的邏輯柠座,然后通過(guò)index+1邑雅,取下一個(gè)攔截器執(zhí)行interceptor.intercept
? RealInterceptorChain next =new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
? ? ? connection, index +1, request, call, eventListener, connectTimeout, readTimeout,
? ? ? writeTimeout);
? Interceptor interceptor =interceptors.get(index);
? Response response = interceptor.intercept(next);
//************省略代碼
return response;
}
其實(shí)這里是一個(gè)責(zé)任鏈模式的一個(gè)應(yīng)用,okhttp框架將網(wǎng)絡(luò)請(qǐng)求的一些步驟封裝成了好幾層(也就是攔截器interceptor)愚隧,根據(jù)之前上面getResponseWithInterceptorChain的截圖可以看到蒂阱,有以下,簡(jiǎn)單描述下各自負(fù)責(zé)的內(nèi)容:
RetryAndFollowUpInterceptor:網(wǎng)絡(luò)請(qǐng)求重試以及重定向請(qǐng)求
BridgeInterceptor:主要處理請(qǐng)求里面Header的相關(guān)狂塘,包括gzip的壓縮解壓縮录煤,cookie等
CacheInterceptor:這里做了緩存相關(guān)策略,比如沒(méi)網(wǎng)絡(luò)時(shí)但有緩存數(shù)據(jù)荞胡,可以直接返回妈踊,還比如說(shuō)后臺(tái)返回的數(shù)據(jù)給了時(shí)效性,下次請(qǐng)求的時(shí)候看到緩存數(shù)據(jù)有效泪漂,這個(gè)時(shí)候直接返回緩存數(shù)據(jù)廊营,節(jié)省了網(wǎng)絡(luò)開(kāi)銷(xiāo)
ConnectInterceptor:這里面有連接池connectionPool歪泳,okhttp是基于socket的一個(gè)封裝,這里有socket連接的緩存
CallServerInterceptor:這里做了最終的網(wǎng)絡(luò)請(qǐng)求操作與服務(wù)端交互
當(dāng)然露筒,這里可以根據(jù)自己的需求自定義攔截器呐伞,實(shí)現(xiàn)自己的邏輯。然后最終的響應(yīng)Response通過(guò)回調(diào)返回后(代碼在AsyncCall#execute())慎式,在finally中調(diào)用了client.dispatcher().finished(this);這個(gè)方法所做的事是從runningAysncCalls中移除這個(gè)已經(jīng)完成的請(qǐng)求伶氢,如果條件滿足,將readyAsyncCalls中的請(qǐng)求添加到runningAysncCalls隊(duì)列中并執(zhí)行
private void finished(Deque calls, T call, boolean promoteCalls) {
int runningCallsCount;
? Runnable idleCallback;
? synchronized (this) {
if (!calls.remove(call))throw new AssertionError("Call wasn't in-flight!");
? ? if (promoteCalls) promoteCalls();
? ? runningCallsCount = runningCallsCount();
? ? idleCallback =this.idleCallback;
? }
if (runningCallsCount ==0 && idleCallback !=null) {
idleCallback.run();
? }
}
private void promoteCalls() {
if (runningAsyncCalls.size() >=maxRequests)return; // Already running max capacity.
? if (readyAsyncCalls.isEmpty())return; // No ready calls to promote.
? for (Iterator i =readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
? ? if (runningCallsForHost(call)
i.remove();
? ? ? runningAsyncCalls.add(call);
? ? ? executorService().execute(call);
? ? }
if (runningAsyncCalls.size() >=maxRequests)return; // Reached max capacity.
? }
}
至此瘪吏,關(guān)于okhttp一個(gè)完整的請(qǐng)求癣防,基本梳理完成。內(nèi)部的一些攔截器相關(guān)內(nèi)容掌眠,后續(xù)有時(shí)間再深挖蕾盯。
這里有一些點(diǎn)需要注意:
1.關(guān)于okhttp里面Dispatcher的線程池創(chuàng)建,這里采用的是SynchronousQueue<Runnable>,采用這個(gè)同步隊(duì)列的原因是希望更快的將runnable交給線程池里面的線程去處理蓝丙,一般來(lái)說(shuō)级遭,SynchronousQueue的size<=1。
2.Dispatcher的線程池線程數(shù)量最大為Integer.MAX_VALUE迅腔,疑問(wèn):這里不設(shè)上限装畅,會(huì)不會(huì)有性能問(wèn)題?答:這里其實(shí)不會(huì)的沧烈,雖然這里沒(méi)做控制但是runningAsyncCalls這個(gè)執(zhí)行中隊(duì)列有做上限處理掠兄,所以不用擔(dān)心。