前言
今天我們來說一說okhttp框架的執(zhí)行流程,這次只說總體流程膛堤,剩下的細(xì)節(jié)我們留在后面說
okhttp的使用
在捋源碼前先回顧一下okhttp是怎么使用的
//創(chuàng)建OkHttpClient
OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();
//創(chuàng)建一個(gè)Request
Request request = new Request.Builder()
.url("https://www.baidu.com").build();
//創(chuàng)建Call
Call call = mOkHttpClient.newCall(request);
//請(qǐng)求加入異步調(diào)度
call.enqueue(new Callback(){
@Override
public void onFailure(@NonNull Call call, @NonNull final IOException e){
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException{
String result = response.body().string();
}
});
分析
1,OkHttpClient
OkHttpClient創(chuàng)建的兩種方式
1晌该,默認(rèn)使用構(gòu)造函數(shù)
public OkHttpClient() {
this(new Builder());
}
2肥荔,使用builder模式
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
...創(chuàng)建初始化參數(shù)...
}
public OkHttpClient build() {
return new OkHttpClient(this);
}
可以看到這兩種方式最后都是將一個(gè)Builder傳遞到OkHttpClient的構(gòu)造函數(shù)里創(chuàng)建的OkHttpClient對(duì)象,一般情況下我們推薦使用第2種的builder模式气笙,因?yàn)槿绻褂玫谝环N的構(gòu)造函數(shù)方法次企,有些參數(shù)是沒法設(shè)置進(jìn)去的
2,Request
Request也是采用builder的方式,這個(gè)比較簡(jiǎn)單潜圃,就是設(shè)置一些請(qǐng)求時(shí)的參數(shù)
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
3缸棵,Call
Call call = mOkHttpClient.newCall(request);
可以看到是使用OkHttpClient.newCall()方法創(chuàng)建的Call對(duì)象,那我們就來看一下newCall這個(gè)方法
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
這里我們看到實(shí)際創(chuàng)建的是RealCall對(duì)象谭期,newRealCall是一個(gè)靜態(tài)方法堵第,這是一個(gè)Factory模式,點(diǎn)到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;
}
首先通過構(gòu)造函數(shù)創(chuàng)建了一個(gè)RealCall對(duì)象隧出,然后設(shè)置一個(gè)eventListener踏志,這個(gè)eventListener我們猜測(cè)應(yīng)該是一個(gè)請(qǐng)求過程的回調(diào),這里先不用管他胀瞪,不影響整體流程的理解针余,繼續(xù)往下看
4,將Call加入到異步調(diào)度
call.enqueue(new Callback(){...});
由于Call實(shí)際上是RealCall凄诞,我們就直接看一下RealCall的enqueue方法實(shí)現(xiàn)
@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));
}
首先是加同步鎖圆雁,判斷是否已經(jīng)執(zhí)行,如果是已經(jīng)執(zhí)行的帆谍,則拋出異常伪朽,防止重復(fù)調(diào)用
然后captureCallStackTrace(),捕獲調(diào)用過程中的堆棧信息
eventListener.callStart(this);回調(diào)通知客戶端請(qǐng)求開始了
client.dispatcher().enqueue(new AsyncCall(responseCallback));加入到異步調(diào)度中,這里要說明一下的是汛蝙,AsyncCall是RealCall的內(nèi)部類烈涮,所以可以直接取到RealCall的所有成員變量
看下client的dispatcher()方法
public Dispatcher dispatcher() {
return dispatcher;
}
直接返回的Dispatcher對(duì)象,那我們繼續(xù)看Dispatcher的enqueue方法
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//加入到運(yùn)行隊(duì)列
runningAsyncCalls.add(call);
//加入到線程池
executorService().execute(call);
} else {
//加入到等待隊(duì)列
readyAsyncCalls.add(call);
}
}
這里是先判斷一下正在運(yùn)行的請(qǐng)求數(shù)是否小于maxRequests(默認(rèn)值是64)窖剑,并且請(qǐng)求當(dāng)前host的請(qǐng)求數(shù)量是否小于maxRequestsPerHost(默認(rèn)值5)坚洽,如果條件都滿足則加入到運(yùn)行隊(duì)列并加入到線程池中開始執(zhí)行,如果不滿足則加入到等待隊(duì)列中
再看一下runningCallsForHost是如何獲取當(dāng)前call的host的請(qǐng)求數(shù)量的
/** 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;
}
可以看到西土,整個(gè)過程就是遍歷runningAsyncCalls讶舰,判斷與當(dāng)前的host相等就計(jì)數(shù)器加一,然后返回;
好绘雁,那么重點(diǎn)來了,把call加入到線程池后援所,他是如何運(yùn)行的呢庐舟?由于是加入到線程池,那么AsyncCall必定是一個(gè)Runnable的實(shí)現(xiàn)類住拭,而且執(zhí)行代碼會(huì)在run方法里挪略,我們看一下
final class AsyncCall extends NamedRunnable {
......
}
這里看到AsyncCall是繼承自NamedRunnable,再看一下NamedRunnable這個(gè)類
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
我們看到這里的run方法首先是設(shè)置了一個(gè)當(dāng)前線程的name滔岳,然后調(diào)用execute方法杠娱,最后再把原來的線程name設(shè)置回來,run主要執(zhí)行的就是這個(gè)execute方法了谱煤,execute是的抽象方法摊求,我們?cè)倩氐紸syncCall看這個(gè)execute方法
@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);
}
}
}
這個(gè)balabala一大堆,但如果簡(jiǎn)化一下看的就明白了
@Override
protected void execute() {
//使用攔截器執(zhí)行網(wǎng)絡(luò)請(qǐng)求刘离,這是okhttp的特色
Response response = getResponseWithInterceptorChain();
//回調(diào)成功或失敗
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
responseCallback.onResponse(RealCall.this, response);
//調(diào)用Dispatcher的finish方法室叉,將當(dāng)前call從運(yùn)行隊(duì)列中移除,并將等待隊(duì)列中的call加入到運(yùn)行隊(duì)列
client.dispatcher().finished(this);
}
主要就是三步硫惕,使用攔截器執(zhí)行網(wǎng)絡(luò)請(qǐng)求茧痕,回調(diào)結(jié)果,然后finished恼除,這里需要重點(diǎn)看一的是getResponseWithInterceptorChain這個(gè)方法
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
//加入應(yīng)用攔截器踪旷,就是用戶添加的攔截器
interceptors.addAll(client.interceptors());
//加入網(wǎng)絡(luò)攔截器
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//加入用戶自定義的網(wǎng)絡(luò)攔截器
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);
}
這個(gè)方法實(shí)現(xiàn)的就是將用戶添加的攔截器和框架自身的網(wǎng)絡(luò)攔截器寫進(jìn)interceptors集合,然后通過RealInterceptorChain去遞歸調(diào)用所有的攔截器豁辉,最后將結(jié)果返回
最后我們?cè)倩剡^頭來看一下 client.dispatcher().finished(this); 這個(gè)方法都做了哪些操作
/** Used by {@code AsyncCall#run} to signal completion. */
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
//實(shí)際調(diào)用的是這個(gè)方法
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
//把當(dāng)前的call從隊(duì)列中移除令野,calls就是runningAsyncCalls
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
//這個(gè)promoteCalls是從上個(gè)函數(shù)傳進(jìn)來的true
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
這個(gè)finished方法將當(dāng)前的call從運(yùn)行隊(duì)列runningAsyncCalls中移除,然后調(diào)用promoteCalls()方法秋忙,然后是一個(gè)閑置狀態(tài)的回調(diào)彩掐,這里我們主要看一下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è)判斷可以忽略掉,看下這個(gè)for循環(huán)灰追,通過迭代器遍歷等待隊(duì)列readyAsyncCalls堵幽,if (runningCallsForHost(call) < maxRequestsPerHost)判斷當(dāng)前host正在的call是否小于最大值,如果是true弹澎,則 i.remove();從等待隊(duì)列中移除朴下,runningAsyncCalls.add(call);executorService().execute(call);加入到運(yùn)行隊(duì)列并加入到線程池中執(zhí),最后一個(gè)判斷是如果運(yùn)行隊(duì)列已滿則返回
這個(gè)方法的作用就是將等待隊(duì)列readyAsyncCalls中的Call加入到運(yùn)行隊(duì)列runningAsyncCalls中
總結(jié)
okhttp的請(qǐng)求過程就是將請(qǐng)求Call加入到線程池中執(zhí)行苦蒿,并同時(shí)加入到隊(duì)列中殴胧;執(zhí)行的過程就是通過一系列的Interceptor最后得到Response返回給客戶端;同步方式與異步方式類似,只是不需要線程池了