okhttp是目前非常常用的網(wǎng)絡(luò)請(qǐng)求框架,我們?cè)谑褂盟耐瑫r(shí)也要看他是怎么實(shí)現(xiàn)的,這篇文章我們簡(jiǎn)單分析以下它的請(qǐng)求流程砾淌。
參考并感謝:https://blog.csdn.net/json_it/article/details/78404010
https://blog.csdn.net/dingding_android/article/details/51942000
https://blog.csdn.net/mwq384807683/article/details/71173442?locationNum=8&fps=1
1稼钩、使用(同步請(qǐng)求)
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("http://www.baidu.com")
.build();
Response response = client.newCall(request).execute();
首先我們new了一個(gè)OkHttpClient對(duì)象,這個(gè)類包含了我們網(wǎng)絡(luò)請(qǐng)求需要的協(xié)議苟呐,http版本協(xié)議痒芝,連接池,調(diào)度器等牵素。之后利用Builder模式創(chuàng)建了請(qǐng)求對(duì)象Request严衬,默認(rèn)的請(qǐng)求方式是get。最后通過newCall(request)創(chuàng)建了Call對(duì)象并執(zhí)行了該對(duì)象的excute方法笆呆。具體分析來看源碼:
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
@Override
public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
我們newCall方法實(shí)際是新建了一個(gè)RealCall對(duì)象瞳步,那么RealCall對(duì)象又是什么呢,RealCall實(shí)際上是實(shí)現(xiàn)了Call接口
public interface Call {
Request request();
Response execute() throws IOException;//同步請(qǐng)求腰奋,會(huì)在當(dāng)前線程執(zhí)行請(qǐng)求并阻塞當(dāng)前線程
void enqueue(Callback responseCallback);//異步請(qǐng)求单起,后面會(huì)分析
void cancel();
boolean isCanceled();
interface Factory {
// 根據(jù)一個(gè)Http請(qǐng)求生成一個(gè)OKHttp請(qǐng)求。
Call newCall(Request request);
}
}
那么RealCall是怎么實(shí)現(xiàn)這些方法呢劣坊?
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
從代碼中可以看到嘀倒,首先判斷這個(gè)請(qǐng)求是否是第一次執(zhí)行,如果是局冰,則繼續(xù)向下執(zhí)行测蘑,否則會(huì)拋出一個(gè)異常,也就是說一個(gè)請(qǐng)求只能執(zhí)行一次康二。
之后碳胳,調(diào)用client.dispatcher().executed(this),即調(diào)用調(diào)度器的excuted方法沫勿,將當(dāng)前請(qǐng)求加入請(qǐng)求隊(duì)列中挨约。內(nèi)部具體的實(shí)現(xiàn)我們?cè)诤竺娈惒秸?qǐng)求中分析。
之后調(diào)用getResponseWithInterceptorChain()得到響應(yīng)Response产雹,并返回诫惭。同步請(qǐng)求分析到這里就結(jié)束了,重頭戲在后面——異步請(qǐng)求蔓挖。
2夕土、異步請(qǐng)求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
這里我們使用RealCall的enqueue方法并傳入一個(gè)CallBack對(duì)象來進(jìn)行回調(diào)
我們來看下enqueue方法的源碼:
@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));
}
同樣的,異步請(qǐng)求首先也要判斷該請(qǐng)求是否是第一次執(zhí)行瘟判。
之后調(diào)用 client.dispatcher().enqueue(new AsyncCall(responseCallback))怨绣,我們的callback對(duì)象被當(dāng)作參數(shù)封裝進(jìn)了AsynCall對(duì)象角溃,我們來看下AsynCall對(duì)象的源碼
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
private final boolean forWebSocket;
private AsyncCall(Callback responseCallback, boolean forWebSocket) {
super("OkHttp %s", originalRequest.url().toString());
this.responseCallback = responseCallback;
this.forWebSocket = forWebSocket;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
Object tag() {
return originalRequest.tag();
}
void cancel() {
RealCall.this.cancel();
}
RealCall get() {
return RealCall.this;
}
/**
過一遍攔截器鏈,并執(zhí)行請(qǐng)求篮撑,然后調(diào)用回調(diào)函數(shù)开镣。
*/
@Override protected void execute() {
// 保證onFailure最多只會(huì)被調(diào)用一次
boolean signalledCallback = false;
try {
// 進(jìn)入連接器鏈,并執(zhí)行請(qǐng)求
Response response = getResponseWithInterceptorChain(forWebSocket);
// 如果請(qǐng)求被取消咽扇,調(diào)用onFailure
if (canceled) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
// 正常情況邪财,調(diào)用onResponse
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
// 如果上面有調(diào)用過回調(diào),就不調(diào)了质欲,這里保證onFailure只會(huì)被調(diào)用一次
if (signalledCallback) {
logger.log(Level.INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
// 運(yùn)行隊(duì)列移除請(qǐng)求
client.dispatcher().finished(this);
}
}
}
可以看到树埠,AsynCall實(shí)際上本身是個(gè)任務(wù),執(zhí)行時(shí)會(huì)調(diào)用execute方法嘶伟,在該方法中我們先調(diào)用Response response = getResponseWithInterceptorChain(forWebSocket)怎憋,通過責(zé)任鏈來獲取response,并執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù)。那么getResponseWithInterceptorChain()這個(gè)方法九昧,就是發(fā)送請(qǐng)求和獲取響應(yīng)的主要核心了绊袋,我們看看具體是怎么實(shí)現(xiàn)的:
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
這里面我們將自定義的攔截器和okhttp自身的攔截器加入至list中,并封裝成一個(gè)責(zé)任鏈對(duì)象Interceptor.Chain铸鹰,最后調(diào)用chain.proceed(request)來執(zhí)行我們的請(qǐng)求并獲得響應(yīng)癌别。那我們?cè)賮砜纯碿hain.proceed里干了些什么
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
......
// Call the next interceptor in the chain.
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;
}
可以看到,proceed方法中判斷index(此時(shí)為0)是否大于或者等于client.interceptors(List )的大小蹋笼。由于httpStream為null展姐,所以首先創(chuàng)建next攔截器鏈,主需要把索引置為index+1即可剖毯;然后獲取第一個(gè)攔截器圾笨,調(diào)用其intercept方法。在intercept方法中我們?cè)僖淮握{(diào)用了chain.proceed的方法去調(diào)用下一個(gè)攔截器的intercept方法逊谋。這樣我們的request請(qǐng)求層層向下傳遞擂达,而最后一個(gè)攔截器處理完畢時(shí),返回的response又層層向上返回胶滋,最后得到的就是最終經(jīng)過加工后的響應(yīng)板鬓。
那么這些攔截器有那些呢?
1)在配置 OkHttpClient 時(shí)設(shè)置的 interceptors镀钓;
2)負(fù)責(zé)失敗重試以及重定向的 RetryAndFollowUpInterceptor穗熬;
3)負(fù)責(zé)把用戶構(gòu)造的請(qǐng)求轉(zhuǎn)換為發(fā)送到服務(wù)器的請(qǐng)求镀迂、把服務(wù)器返回的響應(yīng)轉(zhuǎn)換為用戶友好的響應(yīng)的 BridgeInterceptor丁溅;
4)負(fù)責(zé)讀取緩存直接返回、更新緩存的 CacheInterceptor探遵;
5)負(fù)責(zé)和服務(wù)器建立連接的 ConnectInterceptor窟赏;
6)配置 OkHttpClient 時(shí)設(shè)置的 networkInterceptors妓柜;
7)負(fù)責(zé)向服務(wù)器發(fā)送請(qǐng)求數(shù)據(jù)、從服務(wù)器讀取響應(yīng)數(shù)據(jù)的 CallServerInterceptor涯穷。
請(qǐng)求流程分析到這里棍掐,我們知道我們的請(qǐng)求都是通過調(diào)度器將請(qǐng)求加入請(qǐng)求隊(duì)列中,所以我們最后再來看一下dispatch是如何工作的拷况。
public final class Dispatcher {
/** 最大并發(fā)請(qǐng)求數(shù)為64 */
private int maxRequests = 64;
/** 每個(gè)主機(jī)最大請(qǐng)求數(shù)為5 */
private int maxRequestsPerHost = 5;
/** 線程池 */
private ExecutorService executorService;
/** 準(zhǔn)備執(zhí)行的請(qǐng)求 */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** 正在執(zhí)行的異步請(qǐng)求作煌,包含已經(jīng)取消但未執(zhí)行完的請(qǐng)求 */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** 正在執(zhí)行的同步請(qǐng)求,包含已經(jīng)取消單未執(zhí)行完的請(qǐng)求 */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
再調(diào)度器中赚瘦,創(chuàng)建了一個(gè)線程池
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
該線程池沒有核心線程粟誓,隨時(shí)創(chuàng)建更多線程,阻塞隊(duì)列只保留一個(gè)任務(wù)起意,當(dāng)該任務(wù)被執(zhí)行鹰服,下一個(gè)任務(wù)才能進(jìn)入隊(duì)列。線程的存活時(shí)間為60秒揽咕,60秒還沒有任務(wù)需要執(zhí)行則線程銷毀悲酷。
之后我們來看enqueue方法
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
可以看到如果正在執(zhí)行的請(qǐng)求總數(shù)<=64 && 單個(gè)Host正在執(zhí)行的請(qǐng)求<=5,則將請(qǐng)求加入到runningAsyncCalls集合中亲善,緊接著就是利用線程池執(zhí)行該請(qǐng)求设易,否則就將該請(qǐng)求放入readyAsyncCalls集合中。上面我們已經(jīng)說了蛹头,AsyncCall是Runnable的子類(間接)亡嫌,因此,在線程池中最終會(huì)調(diào)用AsyncCall的execute()方法執(zhí)行異步請(qǐng)求掘而。
這就是okhttp的工作流程挟冠,就分析到這里。