OkHttpClient同步請(qǐng)求的執(zhí)行流程和源碼分析
同步請(qǐng)求示例
OkHttpClient okHttpClient = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build();
Request request = new Request.Builder().url("https://www.baidu.com").get().build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
Log.e(TAG,"response: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
同步請(qǐng)求的步驟
- 創(chuàng)建OkHttpClient對(duì)象和Request對(duì)象,均是采用Builder模式創(chuàng)建,構(gòu)建者(Builder)設(shè)計(jì)模式(又叫生成器設(shè)計(jì)模式)
- 將Request封裝成Call對(duì)象
- 調(diào)用Call的execute()方法發(fā)送同步請(qǐng)求,發(fā)送請(qǐng)求后,就會(huì)進(jìn)入阻塞狀態(tài),直到收到響應(yīng)。
一、(1)OkHttpClient Builder對(duì)象分析
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
??OkHttpClient Builder的構(gòu)造函數(shù),主要是對(duì)一些參數(shù)賦值默認(rèn)值,對(duì)一些對(duì)象進(jìn)行初始化,Dispatcher是OkHttpClient中http請(qǐng)求的分發(fā)器,由它來(lái)決定異步請(qǐng)求是直接處理還是進(jìn)行緩存等待,對(duì)于同步請(qǐng)求,它并沒(méi)有做太多操作,只是把同步請(qǐng)求放到隊(duì)列當(dāng)中去執(zhí)行。ConnectionPool是一個(gè)連接池對(duì)象,用于管理連接對(duì)象,當(dāng)存在同樣的Url請(qǐng)求時(shí),可以復(fù)用,從連接池中找到對(duì)應(yīng)緩存的連接對(duì)象。
(2)Request 對(duì)象分析
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
Request Builder的構(gòu)造函數(shù),默認(rèn)請(qǐng)求方法為GET,同時(shí)初始化一個(gè)Header對(duì)象。
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
build()方法是創(chuàng)建Request對(duì)象,將當(dāng)前的builder對(duì)象傳入,接下來(lái)看Request的構(gòu)造函數(shù):
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tags = Util.immutableMap(builder.tags);
}
??可以看到,是將傳入的Builder對(duì)象中的屬性賦值給Request的相關(guān)屬性,這樣就創(chuàng)建好了Request對(duì)象。
二、創(chuàng)建Call 對(duì)象分析
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
??OkHttpClient 對(duì)象中的newCall()方法,返回值是一個(gè)Call對(duì)象(接口),在這里可以看到實(shí)際上調(diào)用的RealCall.newRealCall()方法創(chuàng)建,RealCall是Call接口的一個(gè)實(shí)現(xiàn)類(lèi),接著查看RealCall類(lèi)中newRealCall()方法:
static RealCall newRealCall(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;
}
??可以看到newRealCall()方法中創(chuàng)建了Call接口的實(shí)現(xiàn)類(lèi)RealCall對(duì)象并返回該對(duì)象,到此Call對(duì)象的創(chuàng)建便完成了。
三、Call 對(duì)象exexcute()方法分析
??上面有提及到Call對(duì)象是一個(gè)接口,我們點(diǎn)擊查看exexcute()方法時(shí),需要點(diǎn)擊查看該方法的實(shí)現(xiàn),實(shí)際上是進(jìn)入到RealCall對(duì)象的exexcute()方法:
@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);
}
}
??在同步代碼中,先通過(guò)判斷executed標(biāo)識(shí),如果當(dāng)前已經(jīng)有在執(zhí)行,則會(huì)拋出"Already Executed"信息的異常,如果沒(méi)有執(zhí)行過(guò),則更改executed標(biāo)識(shí)為true。
??接著調(diào)用captureCallStackTrace()方法,這個(gè)方法主要用于捕捉一些http請(qǐng)求的異常堆棧信息。
??eventListener.callStart(this)開(kāi)啟事件監(jiān)聽(tīng),通過(guò)查看該方法:
/**
* 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) {
}
??通過(guò)閱讀該方法的注釋?zhuān)梢灾涝摲椒〞?huì)在調(diào)用Call對(duì)象的enqueue()或execute()方法的時(shí)候,就會(huì)開(kāi)啟這個(gè)listener。
接下來(lái)分析一下這個(gè)方法中的核心代碼:
client.dispatcher().executed(this);
首先調(diào)用OkHttpClient的dispatcher()方法
public Dispatcher dispatcher() {
return dispatcher;
}
該方法返回一個(gè)Dispatcher對(duì)象,緊接著調(diào)用該對(duì)象的executed()方法:
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
??該方法中,runningSyncCalls是一個(gè)存放同步請(qǐng)求的隊(duì)列,這里僅僅只是將RealCall加入到同步請(qǐng)求的隊(duì)列中,Dispatcher對(duì)象中相關(guān)的隊(duì)列有:
/** 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 是異步請(qǐng)求的就緒隊(duì)列
- runningAsyncCalls 是異步請(qǐng)求的執(zhí)行隊(duì)列
- runningSyncCalls 是同步請(qǐng)求的執(zhí)行隊(duì)列
??調(diào)用完Dispatcher的executed()方法后,緊接著調(diào)用getResponseWithInterceptorChain()方法獲取Response對(duì)象,這個(gè)其實(shí)是一個(gè)攔截器鏈的方法,該方法內(nèi)部會(huì)依次調(diào)用攔截器來(lái)進(jìn)行相應(yīng)的操作。
最后看一下finally中:
finally {
client.dispatcher().finished(this);
}
??通過(guò)調(diào)用Dispatcher的finished()方法,傳入當(dāng)前的RealCall對(duì)象,查看該方法的代碼可以發(fā)現(xiàn):
/** Used by {@code Call#execute} to signal completion. */
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
private <T> void finished(Deque<T> 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();
}
}
??該方法繼續(xù)調(diào)用了其他一個(gè)同名的的方法,將正在執(zhí)行的同步請(qǐng)求隊(duì)列傳了進(jìn)來(lái),在同步代碼塊中,移除掉同步請(qǐng)求隊(duì)列中的call對(duì)象,并進(jìn)行了判斷,如果移除出錯(cuò),則會(huì)拋出異常。接著判斷promoteCalls,由于這里傳入的promoteCalls為false,所以不會(huì)走promoteCalls()方法。
??接著,對(duì)runningCallsCount重新賦值,runningCallsCount用于記錄當(dāng)前正在執(zhí)行的請(qǐng)求數(shù),查看該方法的代碼:
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
該方法很簡(jiǎn)單,即返回正在執(zhí)行的異步請(qǐng)求數(shù)和正在執(zhí)行的同步請(qǐng)求數(shù)的總和。
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
??最后通過(guò)判斷當(dāng)前正在執(zhí)行的請(qǐng)求數(shù),如果當(dāng)前沒(méi)有正在執(zhí)行的請(qǐng)求數(shù)并且有設(shè)置閑置時(shí)的回調(diào),則會(huì)回調(diào)其run()方法。
總結(jié)
??到此,同步請(qǐng)求的執(zhí)行流程就已經(jīng)分析完了,由上述的分析可以知道,在同步請(qǐng)求中,Dispatcher分發(fā)器做的工作非常簡(jiǎn)單,就兩個(gè)操作,保存同步請(qǐng)求和移除同步請(qǐng)求
OkHttpClient異步請(qǐng)求的執(zhí)行流程和源碼分析
異步請(qǐng)求示例
OkHttpClient okHttpClient = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build();
Request request = new Request.Builder().url("https://www.baidu.com").get().build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
異步請(qǐng)求的步驟
- 創(chuàng)建OkHttpClient對(duì)象和Request對(duì)象,均是采用Builder模式創(chuàng)建,構(gòu)建者(Builder)設(shè)計(jì)模式(又叫生成器設(shè)計(jì)模式)
- 將Request封裝成Call對(duì)象
- 調(diào)用Call的enqueue()方法進(jìn)行異步請(qǐng)求
同步和異步的區(qū)別
- 發(fā)起請(qǐng)求的方法調(diào)用
- 阻塞線程與否
源碼分析
??異步請(qǐng)求的前兩步,和同步請(qǐng)求的一致,都是一些準(zhǔn)備工作,并沒(méi)有發(fā)起請(qǐng)求,這里不再重復(fù)說(shuō)明,最主要的是第三步,調(diào)用Call對(duì)象的enqueue()方法,具體的實(shí)現(xiàn)還是在RealCall類(lèi)中,查看該方法代碼:
@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)求的execute()方法相似,主要是 client.dispatcher().enqueue(new AsyncCall(responseCallback)) 這行代碼,調(diào)用Dispatcher的enqueue()方法,將Callback回調(diào)封裝成AsyncCall對(duì)象作為參數(shù)傳入,通過(guò)查看代碼,了解到AsyncCall對(duì)象繼承自NamedRunnable對(duì)象,而NamedRunnable對(duì)象實(shí)現(xiàn)了Runnable接口,接著繼續(xù)查看Dispatcher的enqueue()方法源碼:
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
??該方法前加了synchronized修飾符,是一個(gè)同步方法,根據(jù)判斷當(dāng)前執(zhí)行的異步請(qǐng)求數(shù)是否小于maxRequests(最大請(qǐng)求數(shù),默認(rèn)為64) 且當(dāng)前執(zhí)行的異步請(qǐng)求隊(duì)列中相同主機(jī)的請(qǐng)求數(shù)小于maxRequestsPerHost(每個(gè)主機(jī)最大請(qǐng)求數(shù),默認(rèn)為5) 來(lái)進(jìn)行處理,如果二者都小于設(shè)置的值,則將該請(qǐng)求添加到runningAsyncCalls(異步請(qǐng)求執(zhí)行隊(duì)列)中,否則則添加到readyAsyncCalls(異步請(qǐng)求準(zhǔn)備隊(duì)列)中。
runningCallsForHost()方法的代碼:
/** Returns the number of running calls that share a host with {@code call}. */
private int runningCallsForHost(AsyncCall call) {
int result = 0;
for (AsyncCall c : runningAsyncCalls) {
if (c.get().forWebSocket) continue;
if (c.host().equals(call.host())) result++;
}
return result;
}
??通過(guò)注釋可以知道,該方法返回同一個(gè)主機(jī)的請(qǐng)求數(shù)目,通過(guò)遍歷執(zhí)行中的異步請(qǐng)求隊(duì)列,和傳入的AsyncCall對(duì)象的主機(jī)對(duì)比,如果相同則記錄數(shù)遞增,以此獲得和傳入AsyncCall對(duì)象相同主機(jī)的請(qǐng)求數(shù)。
enqueue()方法中,主要的代碼:
executorService().execute(call);
這里是進(jìn)行異步請(qǐng)求操作的代碼,先看下executorService()方法的代碼:
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;
}
??該方法也是一個(gè)同步方法,主要用于返回 ExecutorService 對(duì)象,在這里僅一次創(chuàng)建了線程池對(duì)象 ThreadPoolExecutor,第二個(gè)參數(shù)傳入了Integer的最大值,即線程池所能容納的最大線程數(shù)為Integer.MAX_VALUE,雖然這里設(shè)置了很大的值,但是實(shí)際情況下并非會(huì)達(dá)到最大值,因?yàn)樯厦鎒nqueue()方法中有做了判斷,主要的還是maxRequests這個(gè)值決定異步請(qǐng)求線程池的最大數(shù)量。
??executorService()方法返回了線程池對(duì)象,接著調(diào)用它的execute()方法,傳入實(shí)現(xiàn)Runnable接口的AsyncCall對(duì)象,上面提及到AsyncCall繼承NamedRunnable,而NamedRunnable對(duì)象實(shí)現(xiàn)了Runnable接口,所以我們想知道該線程池執(zhí)行這個(gè)任務(wù)做了什么,就得看下NamedRunnable對(duì)象的 run() 方法:
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
該方法中,真正的處理邏輯是在execute()方法中:
protected abstract void execute();
而execute()方法是一個(gè)抽象方法,所以要回到繼承NamedRunnable對(duì)象的AsyncCall類(lèi)中:
@Override protected void execute() {
boolean signalledCallback = false;
try {
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 {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
??這里才是真正進(jìn)行異步請(qǐng)求操作的邏輯,同樣也是通過(guò)getResponseWithInterceptorChain()方法得到Response對(duì)象,關(guān)于getResponseWithInterceptorChain()方法的分析在下面的文章里將會(huì)介紹,接著通過(guò)判斷retryAndFollowUpInterceptor是否取消回調(diào)CallBack接口的onFailure()或onResponse()方法,最后finally中,和同步請(qǐng)求的處理一樣,調(diào)用了Dispatcher對(duì)象的finished()方法:
/** Used by {@code AsyncCall#run} to signal completion. */
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
也是調(diào)用了帶三個(gè)參數(shù)的finished()方法,傳入了runningAsyncCalls,call,第三個(gè)參數(shù)傳入了true。
private <T> void finished(Deque<T> 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();
}
}
這里的處理和同步請(qǐng)求結(jié)束后的處理多了一個(gè)promoteCalls()方法的調(diào)用,因?yàn)檫@里promoteCalls傳入了true,所以會(huì)走promoteCalls()方法:
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
??看完這個(gè)方法,會(huì)有一種恍然大悟的感覺(jué),因?yàn)樯厦嬲{(diào)用enqueue()方法的時(shí)候,會(huì)根據(jù)情況將請(qǐng)求添加到runningAsyncCalls(異步請(qǐng)求執(zhí)行隊(duì)列)或readyAsyncCalls(異步請(qǐng)求準(zhǔn)備隊(duì)列)中,而readyAsyncCalls隊(duì)列中的請(qǐng)求什么時(shí)候執(zhí)行呢,相信在看enqueue()方法的時(shí)候會(huì)有這個(gè)疑問(wèn),看了promoteCalls()后疑問(wèn)將會(huì)被解答,為了方便閱讀再次貼上enqueue()方法:
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
??promoteCalls()方法中,首先做了一些判斷,當(dāng)runningAsyncCalls(異步請(qǐng)求執(zhí)行隊(duì)列)已經(jīng)達(dá)到設(shè)置的最大的請(qǐng)求數(shù)或當(dāng)前readyAsyncCalls(異步請(qǐng)求準(zhǔn)備隊(duì)列)中沒(méi)有請(qǐng)求的時(shí)候,則直接返回不做處理,如果滿足條件,則會(huì)遍歷readyAsyncCalls隊(duì)列,將該請(qǐng)求添加到runningAsyncCalls隊(duì)列中,并調(diào)用 executorService().execute(call) 對(duì)該請(qǐng)求進(jìn)行處理。
總結(jié)
??如果異步請(qǐng)求數(shù)超過(guò)最大請(qǐng)求數(shù)或同個(gè)主機(jī)最大請(qǐng)求數(shù)超過(guò)設(shè)置的值的時(shí)候,該請(qǐng)求就會(huì)添加到readyAsyncCalls(異步請(qǐng)求準(zhǔn)備隊(duì)列)中,當(dāng)執(zhí)行完runningAsyncCalls(異步請(qǐng)求執(zhí)行隊(duì)列)的請(qǐng)求后,將會(huì)調(diào)用Dispatcher的finished()三個(gè)參數(shù)的方法,第三個(gè)參數(shù)傳入true,會(huì)調(diào)用promoteCalls()方法,遍歷準(zhǔn)備隊(duì)列readyAsyncCalls,將該隊(duì)列的中的請(qǐng)求添加到執(zhí)行隊(duì)列runningAsyncCalls中,調(diào)用 executorService().execute(call)進(jìn)行處理。
Dispatcher的作用
維護(hù)請(qǐng)求的狀態(tài),并維護(hù)一個(gè)線程池,用于執(zhí)行請(qǐng)求。
異步請(qǐng)求為什么需要兩個(gè)隊(duì)列
異步請(qǐng)求的設(shè)計(jì)可以將其理解成生產(chǎn)者消費(fèi)者模式,其中各個(gè)角色分別為:
- Dispatcher 生產(chǎn)者
- ExecutorService 消費(fèi)者池
- Deque<AsyncCall> readyAsyncCalls 緩存
- Deque<AsyncCall> runningAsyncCalls 正在運(yùn)行的任務(wù)
當(dāng)同步和異步請(qǐng)求結(jié)束后,會(huì)調(diào)用dispatcher的finished方法,將當(dāng)前的請(qǐng)求從隊(duì)列中移除。
下一篇文章中,將為大家講解一下OkHttp的攔截器鏈,感興趣的朋友可以繼續(xù)閱讀:
OkHttpClient源碼分析(二) —— RetryAndFollowUpInterceptor和BridgeInterceptor