原始碼解析一次OKHttp請求的過程
OkHttp這個庫有多優秀作為Androider大家心裡都明白,應該說合格的開發者都認識它。那麼,這裡簡單看個OKHttp的介面請求姿勢:
OkHttpClient okHttpClient = new OkHttpClient(); Request request = new Request.Builder() .url("https://www.xxxx.com/xxx/xxx/xxx") .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 { // 這裡介面請求成功 } });
所以很明顯了弄懂了上面幾個類的是幹嘛、上個幾個流程做了什麼自然就明白了OKHttp的執行流程了,那麼就開始分析吧。
OKHttp請求中需要的物件
Request
這個類是典型的’Builder’設計模式,看一眼他的成員屬性就知道這個類是幹嘛的了。
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
final Object tag;
.
.
.
}
看看變數名就知道了這個類封裝那些玩意,還是很愉快的完成了一小步。
OkHttpClient
這個類類似個Manager類,裡面的成員屬性自然也比較多了。
我們重點關注Dispatcher這個執行緒池屬性:
// 可以傳入執行緒池,從而自定義OKHttp執行緒池 public Dispatcher(ExecutorService executorService) { this.executorService = executorService; } public Dispatcher() { } // 初始化執行緒池 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; }
所以Dispatcher
就是一個執行緒池管理類,用於分發每一次的Http請求。
Call
是介面真正的實現類是RealCall
,而RealCall
有個內部類叫AsyncCall
是個介面,最終加入Dispatcher
執行緒池的就是AsyncCall
物件。
執行Http請求操作
我們從okHttpClient.newCall操作開始閱讀:
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
所以這裡封裝了一個RealCall
物件然後執行enqueue方法,我們進入該方法看看一下程式碼:
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
再看最後一行程式碼會執行Dispatcher.enqueue
方法,同樣的進入看看程式碼怎麼執行的:
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
由於AsyncCall
是實現了NamedRunnable
介面,所以執行緒池就會執行NamedRunnable.run
方法,這樣子自然就執行到AsyncCall.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 {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
我們可以看到這裡直接通過getResponseWithInterceptorChain()方法直接得到Response然後通過Callback回撥資料回去。
攔截器Interceptor
通過上面我們知道已經得到Response基本上可以說已經結束了一個流程,這裡並不細節的解釋每個攔截器的程式碼,只是介紹一下攔截器的呼叫時序,所以仍然先看一下getResponseWithInterceptorChain方法:
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
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);
return chain.proceed(originalRequest);
}
我們可以看到系統已經為我們定義幾個預設的攔截器,他們的作用一起呼叫時序如下: 這裡知道了呼叫時序,那從什麼時候觸發呼叫?
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
我們可以看到是先封裝一個RealInterceptorChain物件,然後執行proceed方法自然就會執行每一個interceptor.intercept方法。OKHttp的所有精髓之一就是攔截器的使用…
最後,這裡我們也可以明白一點addInterceptor / addNetworkInterceptor兩者之間有何不同了,因為他們倆的呼叫時序不一樣。
更多攔截器的分析,將在未來找時間分析。