本人通過源碼的解讀,只是為了加深對(duì)其執(zhí)行流程的理解,文章中不會(huì)對(duì)更細(xì)致的地方做過多的講解,只是把握住開源框架的整體脈絡(luò)。
首先放上一個(gè)簡(jiǎn)單使用的例子:
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder().url("http://www.baidu.com").build();
Call call = client.newCall(request);
//同步請(qǐng)求
try {
Response response = call.execute();
response.close();
} catch (IOException e) {
e.printStackTrace();
}
//異步請(qǐng)求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//todo failure
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//todo response
}
});
如上可以看到OkHttp有兩種數(shù)據(jù)請(qǐng)求方式:同步和異步,其中請(qǐng)求Call是一個(gè)接口,實(shí)際由RealCall執(zhí)行。
同步請(qǐng)求方式
public Response execute() throws IOException {
......
Response var2;
try {
...
Response result = this.getResponseWithInterceptorChain();
...
var2 = result;
} catch (IOException var7) {
this.eventListener.callFailed(this, var7);
throw var7;
} finally {
this.client.dispatcher().finished(this);
}
return var2;
}
getResponseWithInterceptorChain是一個(gè)鏈?zhǔn)秸{(diào)用的一個(gè)方法,該方法是OkHttp的一個(gè)精華部分,暫且不講。
整個(gè)同步請(qǐng)求方式還是比較簡(jiǎn)單的,Call通過execute方法直接請(qǐng)求數(shù)據(jù),以及接受數(shù)據(jù)成功或者失敗的回調(diào)。
異步請(qǐng)求方式
// RealCall.java
public void enqueue(Callback responseCallback) {
......
this.client.dispatcher().enqueue(new RealCall.AsyncCall(responseCallback));
}
// Dispatcher.java
/**
* 這里有個(gè)小細(xì)節(jié),異步請(qǐng)求不會(huì)是用多少請(qǐng)求就一定會(huì)立即會(huì)開始多少條請(qǐng)求,而是有個(gè)請(qǐng)求數(shù)量上限的。
* 只有執(zhí)行隊(duì)列的數(shù)量<最大請(qǐng)求數(shù),并且正在請(qǐng)求的host數(shù)<最大請(qǐng)求host數(shù)時(shí)才會(huì)請(qǐng)求,否則就暫時(shí)放在就緒隊(duì)列里緩存起來
*/
synchronized void enqueue(AsyncCall call) {
if(this.runningAsyncCalls.size() < this.maxRequests
&& this.runningCallsForHost(call) < this.maxRequestsPerHost) {
this.runningAsyncCalls.add(call);
this.executorService().execute(call);
} else {
this.readyAsyncCalls.add(call);
}
}
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
......
protected void execute() {
boolean signalledCallback = false;
try {
// 1、請(qǐng)求結(jié)果
Response response = RealCall.this.getResponseWithInterceptorChain();
// 2、結(jié)果回調(diào)
if(RealCall.this.retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
this.responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
this.responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException var6) {
// 3、失敗處理
if(signalledCallback) {
Platform.get().log(4, "Callback failure for " + RealCall.this.toLoggableString(), var6);
} else {
RealCall.this.eventListener.callFailed(RealCall.this, var6);
this.responseCallback.onFailure(RealCall.this, var6);
}
} finally {
// 4、結(jié)束
RealCall.this.client.dispatcher().finished(this);
}
}
}
public abstract class NamedRunnable implements Runnable {
public final void run() {
...
this.execute();
...
}
protected abstract void execute();
}
如上流程可以看出,異步方式就是將RealCall通過包裝成AsyncCall,然后在線程池中進(jìn)行數(shù)據(jù)請(qǐng)求,然后執(zhí)行返回?cái)?shù)據(jù)成功或者失敗的處理。
通過以上的分析可以看出,OkHttp無論同步還是異步數(shù)據(jù)請(qǐng)求,整體的邏輯還是比較簡(jiǎn)單的,同步就直接在主線程中進(jìn)行數(shù)據(jù)請(qǐng)求,異步就是在異步線程池中進(jìn)行數(shù)據(jù)請(qǐng)求
無論同步還是異步請(qǐng)求,都有一個(gè)非常重要的一個(gè)方法:getResponseWithInterceptorChain(),這個(gè)方法也是OkHttp的精髓所在。下面具體開始分析該方法的實(shí)現(xiàn)。
getResponseWithInterceptorChain方法的實(shí)現(xiàn)邏輯分析
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList();
// 用戶自定義的攔截器列表
interceptors.addAll(this.client.interceptors());
interceptors.add(this.retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(this.client.cookieJar()));
interceptors.add(new CacheInterceptor(this.client.internalCache()));
interceptors.add(new ConnectInterceptor(this.client));
if(!this.forWebSocket) {
interceptors.addAll(this.client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(this.forWebSocket));
// 注意第5個(gè)參數(shù)傳遞的是0
Chain chain = new RealInterceptorChain(interceptors, (StreamAllocation)null, (HttpCodec)null, (RealConnection)null, 0, this.originalRequest, this, this.eventListener, this.client.connectTimeoutMillis(), this.client.readTimeoutMillis(), this.client.writeTimeoutMillis());
return chain.proceed(this.originalRequest);
}
如上可以看出OkHttp除了用戶自定義的攔截器之外,主要包括如下幾個(gè)攔截器RetryAndFollowUpInterceptor、BridgeInterceptor、CacheInterceptor、ConnectInterceptor、NetworkInterceptor和CallServerInterceptor。這幾大攔截器共同組成了一個(gè)攔截器鏈,并封裝到RealInterceptorChain這個(gè)對(duì)象當(dāng)中。
既然是個(gè)攔截鏈,那OkHttp又是如何一條鏈一條鏈來進(jìn)行數(shù)據(jù)攔截的呢?
下面再看看它的proceed的實(shí)現(xiàn):
public Response proceed(Request request) throws IOException {
return this.proceed(request, this.streamAllocation, this.httpCodec, this.connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException {
...
// 注意第5個(gè)參數(shù)為index+1
RealInterceptorChain next = new RealInterceptorChain(this.interceptors, streamAllocation, httpCodec, connection, this.index + 1, request, this.call, this.eventListener, this.connectTimeout, this.readTimeout, this.writeTimeout);
Interceptor interceptor = (Interceptor)this.interceptors.get(this.index);
Response response = interceptor.intercept(next);
...
return response;
}
這里大家只看到了其似乎只提取了一條攔截器,如何才能鏈?zhǔn)秸{(diào)用攔截器?這就是OkHttp設(shè)計(jì)的一個(gè)巧妙之處,正是通過interceptor.intercept(next)來不斷的獲取下一條攔截器進(jìn)行數(shù)據(jù)攔截,然后返回最終的response。
Intercepter是一個(gè)接口,這里我拿RetryAndFollowUpInterceptor舉例:
public Response intercept(Chain chain) throws IOException {
......
RealInterceptorChain realChain = (RealInterceptorChain)chain;
response = realChain.proceed(request, this.streamAllocation, (HttpCodec)null, (RealConnection)null);
......
return response;
}
看到?jīng)]有,類似這個(gè)攔截器一樣,每個(gè)攔截器都會(huì)最終調(diào)用realChain.proceed來不斷獲取下一個(gè)攔截器對(duì)返回?cái)?shù)據(jù)進(jìn)行攔截處理,從而最終得到處理后成功或者失敗的數(shù)據(jù)。