OkHttp不同版本的代碼差異挺大的瘟斜,本篇文章中分析的源碼是基于OkHttp 3.6.0版本進(jìn)行的。
- 《OkHttp Request 請求執(zhí)行流程》
- 《OkHttp - Interceptors(一)》
- 《OkHttp - Interceptors(二)》
- 《OkHttp - Interceptors(三)》
- 《OkHttp - Interceptors(四)》
一艰亮、 Request任務(wù)的調(diào)度
為了分析OkHttp種一次請求的流程厅缺,我們先從最簡單的請求示例開始供搀,OkHttp中請求分成同步和異步兩種:
同步請求
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
Response response = client.newCall(request).execute();
異步請求
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
這兩種請求方式都是通過創(chuàng)建一個Call來發(fā)起的郊供,區(qū)別在于同步請求直接調(diào)用execute()在當(dāng)前線程執(zhí)行,而異步請求則是調(diào)用enqueue()將任務(wù)加入到隊(duì)列之中须揣,由調(diào)度器Dispatcher決定什么時候發(fā)起請求盐股。
同步請求在實(shí)際開始執(zhí)行請求之前調(diào)用了dispatcher.execute()將自己加入正在執(zhí)行的請求列表,并在請求結(jié)束后調(diào)用dispatcher.finish()從執(zhí)行列表中移除耻卡,這主要是為了統(tǒng)一管理執(zhí)行中的任務(wù)疯汁。
Dispatcher在異步請求中發(fā)揮了重要的作用,其中創(chuàng)建了一個線程池用于異步執(zhí)行請求任務(wù)卵酪,還可以通過setMaxRequests()設(shè)置同時允許執(zhí)行的最大請求數(shù)幌蚊,以及setMaxRequestsPerHost()設(shè)置相同host下最多運(yùn)行的請求數(shù)。
synchronized void enqueue(AsyncCall call) {
// 正在執(zhí)行的總?cè)蝿?wù)數(shù)及相同host下正在執(zhí)行的任務(wù)數(shù)小于閾值時溃卡,直接執(zhí)行任務(wù)
if(runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else { // 加入等待隊(duì)列
readyAsyncCalls.add(call);
}
}
當(dāng)正在執(zhí)行的任務(wù)總數(shù)及相同host下的任務(wù)數(shù)小于最大值時溢豆,直接執(zhí)行當(dāng)前請求,而任務(wù)數(shù)超過限定時瘸羡,將其加入等待隊(duì)列漩仙。
AsyncCall繼承于Runnable,相當(dāng)于是對RealCall的一次包裝犹赖。
protected void execute() {
boolean signalledCallback = false;
try {
// 執(zhí)行實(shí)際的網(wǎng)絡(luò)請求
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
// 通知 dispatcher 已完成當(dāng)前請求队他,開始執(zhí)行任務(wù)調(diào)度
client.dispatcher().finished(this);
}
}
}
getResponseWithInterceptorChain()中完成實(shí)際的網(wǎng)絡(luò)請求,在執(zhí)行完畢后調(diào)用finished方法通知dispatcher執(zhí)行任務(wù)調(diào)度峻村,最終的調(diào)度任務(wù)在promoteCalls中執(zhí)行麸折。
private void promoteCalls() {
// 正在執(zhí)行的任務(wù)數(shù)任大于閾值,不調(diào)度
if (runningAsyncCalls.size() >= maxRequests) return;
// 無等待中任務(wù)
if (readyAsyncCalls.isEmpty()) return;
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
// 執(zhí)行等待中任務(wù)
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
// 已達(dá)閾值粘昨,結(jié)束調(diào)度
if (runningAsyncCalls.size() >= maxRequests) return;
}
}
每次異步請求執(zhí)行結(jié)束后都會拉起正在等待隊(duì)列中的請求任務(wù)叨襟。
二、Request執(zhí)行流程
上面我們看到實(shí)際的請求是在getResponseWithInterceptorChain()中完成的,那么我們來看看其中發(fā)生了什么。
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
// 自定義攔截器
interceptors.addAll(client.interceptors());
// 重定向攔截器
interceptors.add(retryAndFollowUpInterceptor);
// 橋接攔截器(處理header 低散、cookie 等)
interceptors.add(new BridgeInterceptor(client.cookieJar()));
// 緩存攔截器(處理 cache)
interceptors.add(new CacheInterceptor(client.internalCache()));
// 連接攔截器(負(fù)責(zé)建立連接)
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
// 自定義網(wǎng)絡(luò)攔截器(此時已建立連接)
interceptors.addAll(client.networkInterceptors());
}
// 服務(wù)請求攔截器(發(fā)起請求、接收響應(yīng))
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
這里創(chuàng)建了一個 Interceptor 的列表快集,按照用戶自定義的 Interceptor笛臣、RetryAndFollowUpInterceptor、BridgeInterceptor尸饺、CacheInterceptor进统、ConnectInterceptor、自定義的 network Interceptor浪听、CallServerInterceptor的順序?qū)⑦@些攔截器添加到列表中螟碎,后面可以看到這個順序就是請求實(shí)際執(zhí)行的順序。
在請求的過程中迹栓,OkHttp 使用了責(zé)任鏈模式來一步步完成請求掉分,這個責(zé)任鏈就是由RealInterceptorChain來實(shí)現(xiàn)的。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, Connection connection) throws IOException {
// 省略部分無關(guān)代碼
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// ...
return response;
}
在 proceed 中根據(jù) index 依次獲取之前傳入的 interceptor 處理請求克伊,同時創(chuàng)建了鏈?zhǔn)焦?jié)點(diǎn)傳遞給下一個攔截器酥郭,以便下一個攔截器處理完自己的任務(wù)后調(diào)用。以ConnectInterceptor為例:
public final class ConnectInterceptor implements Interceptor {
public final OkHttpClient client;
public ConnectInterceptor(OkHttpClient client) {
this.client = client;
}
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
boolean doExtensiveHealthChecks = !request.method().equals("GET");
// 創(chuàng)建解碼器愿吹,并建立連接
HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
// 將請求交給下一個攔截器處理
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
}
OkHttp 中的請求流程可以用下面這張圖來描述不从。
總之,請求是以鏈?zhǔn)降男问揭徊讲竭M(jìn)行犁跪,所有的攔截器完成自己的任務(wù)后就將請求傳遞給下一個攔截器進(jìn)行處理椿息,直到最后請求執(zhí)行完畢。