同步請求
1传泊、創(chuàng)建一個請求對象
Call call = OkHttpClient.newCall(this);
2暖侨、獲取請求結(jié)果
call.execute();
Call 對象exexcute()方法分析
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
timeout.enter();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
e = timeoutExit(e);
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
在同步代碼中,先通過判斷executed標(biāo)識支竹,如果當(dāng)前已經(jīng)有在執(zhí)行,則會拋出"Already Executed"信息的異常鸠按,如果沒有執(zhí)行過礼搁,則更改executed標(biāo)識為true。一個任務(wù)只能執(zhí)行一次
captureCallStackTrace()方法:
主要用于捕捉一些http請求的異常堆棧信息
eventListener.callStart(this)方法:
開啟事件監(jiān)聽
該方法源碼
/**
* Invoked as soon as a call is enqueued or executed by a client. In case of thread or stream
* limits, this call may be executed well before processing the request is able to begin.
*
* <p>This will be invoked only once for a single {@link Call}. Retries of different routes
* or redirects will be handled within the boundaries of a single callStart and {@link
* #callEnd}/{@link #callFailed} pair.
*/
public void callStart(Call call) {
}
該方法
一旦調(diào)用被客戶端排隊或執(zhí)行目尖,就會立即調(diào)用馒吴。在線程或流受限的情況下,次調(diào)用可能在處理請求能在開始之前調(diào)用,也就是說該方法會在調(diào)用Call對象的enqueue()或execute()方法的時候饮戳,就會開啟這個listener
client.dispatcher().executed(this)方法
受限調(diào)用OkHttpClient的dispatcher()方法豪治,該方法返回一個Dispatcher對象,緊接著調(diào)用該對象的executed()方法莹捡;該方法中鬼吵,runningSyncCalls是一個存放同步請求的隊列,這里僅僅只是將RealCall加入到同步請求的隊列中
Dispatcher對象中相關(guān)的隊列有:
/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
readyAsyncCalls 是異步請求的就緒隊列
runningAsyncCalls 是異步請求的執(zhí)行隊列
runningSyncCalls 是同步請求的執(zhí)行隊列
3篮赢、Response result = getResponseWithInterceptorChain()方法
獲取請求結(jié)果齿椅,由此可見,同步請求并沒有使用線程池
也沒有開啟子線程
4启泣、client.dispatcher().finished(this)方法
在finally中執(zhí)行
通過調(diào)用Dispatcher的finished()方法涣脚,傳入當(dāng)前的RealCall對象
/** Used by {@code Call#execute} to signal completion. */
void finished(RealCall call) {
finished(runningSyncCalls, call);
}
private <T> void finished(Deque<T> calls, T call) {
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
idleCallback = this.idleCallback;
}
boolean isRunning = promoteAndExecute();
if (!isRunning && idleCallback != null) {
idleCallback.run();
}
}
該方法繼續(xù)調(diào)用了其他一個同名的的方法,將正在執(zhí)行的同步請求隊列傳了進(jìn)來寥茫,在同步代碼塊中遣蚀,移除掉同步請求隊列中的call對象,并進(jìn)行了判斷纱耻,如果移除出錯芭梯,則會拋出異常。接著判斷promoteCalls弄喘,由于這里傳入的promoteCalls為false玖喘,所以不會走promoteCalls()方法。
異步請求
@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));
}
client.dispatcher().enqueue(new AsyncCall(responseCallback))
調(diào)用Dispatcher的enqueue()方法蘑志,將Callback回調(diào)封裝成AsyncCall對象作為參數(shù)傳入
AsyncCall對象繼承自NamedRunnable對象累奈,而NamedRunnable對象實現(xiàn)了Runnable接口
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
該方法前加了synchronized修飾符,是一個同步方法急但,根據(jù)判斷當(dāng)前執(zhí)行的異步請求數(shù)是否小于maxRequests(最大請求數(shù)澎媒,默認(rèn)為64) 且當(dāng)前執(zhí)行的異步請求隊列中相同主機(jī)的請求數(shù)小于maxRequestsPerHost(每個主機(jī)最大請求數(shù),默認(rèn)為5) 來進(jìn)行處理波桩,如果二者都小于設(shè)置的值戒努,則將該請求添加到runningAsyncCalls(異步請求執(zhí)行隊列)中,否則則添加到readyAsyncCalls(異步請求準(zhǔn)備隊列)中镐躲。