OkHttp原始碼解析(一)
簡單使用
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Request request = new Request.Builder()
.url("www.baidu.com")
.build();
Call call = okHttpClient.newCall(request);
//同步請求
try {
Response response = call.execute();
} catch (IOException e) {
e.printStackTrace( );
}
//非同步請求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {}
@Override
public void onResponse(Call call, Response response) throws IOException {}
});
它的用法也是比較簡單,前三步中非同步跟同步的操作基本是一樣的,就是最後稍有不同,好,我們現在就來逐一進行解析。
原始碼解析
-
OkHttpClient
首先我們來看看OkHttpClient例項的建立 OkHttpClient okHttpClient = new OkHttpClient.Builder().build() 它首先是通過一個構建者模式來建立它的一個例項。
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;
}
而Builder類是OkHttpClient的一個內部類,通過呼叫它的build方法就會把OkHttpClient的例項創建出來
public OkHttpClient build() {
return new OkHttpClient(this);
}
-
Request
把OkHttpClient例項創建出來之後,接著就是Request的建立。其實它的建立跟OkHttpClient的建立大同小異,也是通過builder構建者模式建立的,不過有一點需要注意: 它預設的請求方法是get。
-
Call
Call call = okHttpClient.newCall(request);
這個Call其實只是一個介面,因此不能直接建立它的例項,只能是去建立它的子類。
public interface Call extends Cloneable {
/** Returns the original request that initiated this call. */
Request request();
Response execute() throws IOException;
void enqueue(Callback responseCallback);
void cancel();
boolean isExecuted();
boolean isCanceled();
Call clone();
interface Factory {
Call newCall(Request request);
}
}
這裡它是利用我們剛剛建立好的okHttpClient例項的newCall方法進行建立,好我們就走進去看看:
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
我們發現它這裡是通過RealCall的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;
}
這裡我們主要看第一行,直接就是建立了RealCall的例項,而這個RealCall也是實現了Call介面的,我們看看這個RealCall的構造方法:
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
這裡傳遞了OkHttpClient、Request的例項,還有就是建立了RetryAndFollowUpInterceptor這個攔截器類,攔截器在後面會有講解,這是非常重要的一點。
因為同步和非同步的前三步都是一樣的,那我們現在來看看最後一步大家有什麼區別。
1. 同步
同步的話就會去呼叫Call的execute方法,從上面的講解也知道Call是一個介面,所以呼叫的是它的實現類RealCall。
@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);
}
}
這裡首先就會去判斷executed這個標誌位是否為true,因為同一個請求只能是請求一次。 接下去往下看這句client.dispatcher().executed(this)。 這裡會呼叫client.dispatcher的exceuted方法。而client的dispatcher方法獲取的就是Dispatcher這個例項,這個類的例項是在構建OkHttpClient的時候建立的。Dispatcher這個類是很重要的一個類,它維護請求的狀態(同步還是非同步),並且維護一個執行緒池,用於執行請求,這從後面可以知道。那我們現在看看它的executed方法:
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
這裡出現了一個runningSyncCalls這個變數,究竟是什麼呢?我們看看它的定義,也是在Dispatcher這個類裡面:
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
其實它就是一個佇列,當有同步請求的時候,就會把這個Call新增到一個同步佇列中去。
回到RealCall的executed方法中去,把RealCall新增到同步佇列之後,就會去呼叫getResponseWithInterceptorChain()這個方法獲取Response,這個方法可以說是整個OkHttp最重要的部分,攔截器鏈,這裡我們留到下一章節來說。現在我們來看看finally那部分:
client.dispatcher().finished(this);
這裡會呼叫Dispatcher的finish方法,裡面做了什麼,我們進去看看:
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();
}
}
它這裡會把同步佇列runningSyncCalls和當前的Call作為引數傳到finished的過載方法中。在這個過載方法裡面可以看到,它會把這個同步的Call從佇列中移除。因為傳進來的promoteCalls是為false,所以promoteCalls這個方法就不會執行,接下來就會呼叫runningCallsCount()這個方法,從名字上我們可以猜測它應該是統計Call的數量:
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
它是在統計兩個佇列的數量,runningAsyncCalls是接下來會講解到執行中的非同步佇列。這樣同步的講解完了,接下來就要看看非同步的了。
2. 非同步
非同步呼叫的是Call的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));
}
同樣的,我們只需要看最後一行,它首先new了一個AsyncCall例項,我們看看它的定義
final class AsyncCall extends NamedRunnable
它是RealCall裡面的一個內部類,而它又繼承了一個NamedRunnable,我們又繼續看看這個NameRunnable:
public abstract class NamedRunnable implements Runnable
現在終於明白了,原來這個AsyncCall就是一個Runnable執行緒。好我們看回Dispatcher的enqueue的這個方法
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
這裡有幾個變數,我們先來看看它的定義:
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
/** 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<>();
這幾個都是Dispatcher的成員變數 maxRequests:最大可執行的執行緒數 maxRequestsPerHost:最大的主機數 readyAsyncCalls:非同步的就緒佇列 runningAsyncCalls:非同步的執行佇列
回到enqueue方法,若條件不符合的時候,就會把Call新增到非同步的就緒佇列中等待;若條件成立的話就會把Call新增到執行佇列,然後呼叫executorService().execute(call)。這裡出現了一個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;
}
這裡會返回一個執行緒池,在Dispatcher類中也是維護了一個自己的執行緒池來執行AsyncCall。那我們來看看AsyncCall的run方法,但是AsyncCall裡面並沒有run方法,而它的run方法是在它的父類NamedRunnable中,而最終也是會呼叫execute方法,所以我們看看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 {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
同樣的,這裡會呼叫getResponseWithInterceptorChain()這個方法獲取Response,後面會講到,然後就處理回撥訊息。同樣的我們也要看看finally裡面的finished方法。
/** Used by {@code AsyncCall#run} to signal completion. */
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, 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();
}
}
這裡跟同步裡面的finished方法差不多,其中的一個區別就是promoteCalls是為true的,所以就會去呼叫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.
}
}
這裡首先會判斷正在執行的非同步佇列數量有沒有超過最大限值,然後就是遍歷這個非同步的就緒佇列,把就緒佇列中的AsyncCall新增到執行佇列中,並且放到執行緒池中執行。
下一節就會去講解這個攔截器鏈,感謝!