閱讀指南:
本博客,前面源碼部分,duck不必細看,大概瞄一眼就行,或只看我加註釋的部分就行。我會在文末描述下大概流程把流程理清楚了再看代碼比較好,看代碼注意只看主要流程,其他分支末節,有時間自己慢慢研究就行。
使用
沒什麼好說的,記住這麼用就好。
val okHttpClient = OkHttpClient()
val request = Request.Builder()
.url("https://xxxx")
.build()
val call = okHttpClient.newCall(request)
call.enqueue(object :okhttp3.Callback{
override fun onFailure(call: okhttp3.Call, e: IOException) {
}
override fun onResponse(call: okhttp3.Call, response: okhttp3.Response){
}
})
OkHttpClient
OkHttpClient 構造方法的各種參數,瞭解一下就好,也可以直接跳過。
//建造者模式
public OkHttpClient() {
this(new Builder());
}
//就是一些初始化的參數大概看一看就好
public static final class Builder {
//用於調度線程的
Dispatcher dispatcher;
//網絡代理
@Nullable Proxy proxy;
//支持的協議的版本
List<Protocol> protocols;
//支持http、https的配置,https的各種加密協議
List<ConnectionSpec> connectionSpecs;
//攔截器
this.interceptors.addAll(okHttpClient.interceptors);
this.networkInterceptors.addAll(okHttpClient.networkInterceptors);
//做統計相關的
EventListener.Factory eventListenerFactor
ProxySelector proxySelector;
//餅乾罐子,存儲cookie用的
CookieJar cookieJar;
//httpCache
@Nullable Cache cache;
@Nullable InternalCache internalCache;
//獲取連接端口,socket是TCP的東西
SocketFactory socketFactory;
//SSL連接的Factory
@Nullable SSLSocketFactory sslSocketFactory;
//服務器證書
@Nullable CertificateChainCleaner certificateChainCleaner;
//主機名驗證器,for https。
HostnameVerifier hostnameVerifier;
//自簽名證書的驗證,利用公鑰來驗證的。
CertificatePinner certificatePinner;
//授權用的(代理用的)
Authenticator proxyAuthenticator;
//正常用的授權
Authenticator authenticator;
//連接池,待緩存的集合
ConnectionPool connectionPool;
Dns dns;
//重定向時候有一個https,可能是跳過去,可能是跳過來
boolean followSslRedirects;
//重定向跳轉
boolean followRedirects;
//連接失敗了是否要重新連接
boolean retryOnConnectionFailure;
int callTimeout;
//TCP連接時間
int connectTimeout;
int readTimeout;
int writeTimeout;
//針對websocket的
int pingInterval;
}
execute
call.execute()
這是同步的執行方法。
@Override public Response execute() throws IOException {
//如果執行過,就報錯
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//transmitter 發射臺的意思,先忽略下面兩句
transmitter.timeoutEnter();
transmitter.callStart();
try {
//重點:dispatcher執行這個Call,對應下面的加入runningSyncCalls
client.dispatcher().executed(this);
//這行直接跳轉下面標題
return getResponseWithInterceptorChain();
} finally {
client.dispatcher().finished(this);
}
}
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
//加入正在執行的雙端隊列
runningSyncCalls.add(call);
}
enqueue
//異步方法
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
//看這行
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
//responseCallback封裝一個AsyncCall,並加入 readyAsyncCalls
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
promoteAndExecute();
}
接下來,我們從AsyncCall中找繼續執行的方法,發現這個 AsyncCall 繼承了一個 NamedRunnable implements Runnable,然後我們閱讀 run() 方法。
/**
* Runnable implementation which always sets its thread name.
*/
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
//找到 run 方法了
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
//發現裏面調用了execute,是一個抽象類的抽象方法,去子類 AsyncCall 中找 execute 方法
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
//找到啦!
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
//發現,還是走到了一個關鍵的方法,這個在下面有解析
Response response = getResponseWithInterceptorChain();
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);
}
} catch (Throwable t) {
cancel();
if (!signalledCallback) {
IOException canceledException = new IOException("canceled due to " + t);
canceledException.addSuppressed(t);
responseCallback.onFailure(RealCall.this, canceledException);
}
throw t;
} finally {
client.dispatcher().finished(this);
}
}
dispatcher
這個裏面有三個雙向隊列。一個是爲同步使用的,另外兩個是爲異步使用的。
這個類裏面初始化了線程池,用線程池來處理線程,提高了程序的性能,爲異步操作提供的。
/** 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<>();
//線程池的初始化方法
public synchronized ExecutorService executorService() {
if (executorService == null) {
//可以看一下各個參數的意義
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
//promoteAndExecute 方法是線程池的 start 方法
/**
* Promotes eligible calls from {@link #readyAsyncCalls} to {@link #runningAsyncCalls} and runs
* them on the executor service. Must not be called with synchronization because executing calls
* can call into user code.
*
* @return true if the dispatcher is currently running calls.
*/
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
//對 readyAsyncCalls 進行遍歷
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
//兩個判斷,一個事判斷最大請求數>=64,一個是每個主機的請求數 >= 5
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
asyncCall.callsPerHost().incrementAndGet();
executableCalls.add(asyncCall);
//添加到 runningAsyncCalls
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//執行這個 AsyncCall
asyncCall.executeOn(executorService());
}
return isRunning;
}
getResponseWithInterceptorChain(重點啊)
責任鏈模式
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
//添加一大堆的攔截器
interceptors.addAll(client.interceptors());
interceptors.add(new RetryAndFollowUpInterceptor(client));
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));
//這個chain把所有的攔截器都裝了進去
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
//然後開始調用 chain 的 Proceed 方法
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
//chain只有一個實現類就是RealInterceptorChain,所以我們來到這個類的 proceed 方法
@Override public Response proceed(Request request) throws IOException {
return proceed(request, transmitter, exchange);
}
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException {
//判斷錯誤,不用看
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.exchange != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
// index 從0開始,在上面調用的代碼中有描述
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
//開始調用各個攔截器的 intercept 方法,所有的攔截器都 implements 了 Interceptor,跳轉到分析 RetryAndFollowUpInterceptor(默認這是第一個)
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (exchange != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;
}
RetryAndFollowUpInterceptor implements Interceptor
Interceptor 這個接口類中只有一個方法
Response intercept(Chain chain) throws IOException;
其次還有一個 Chain 類,其中有一個關鍵方法,叫 proceed
Response proceed(Request request) throws IOException;
我們從 RetryAndFollowUpInterceptor 開始看,我們先分析這個責任鏈模式。
我們可以把 RetryAndFollowUpInterceptor 這個類的 intercept 簡化爲下面代碼
@Override public Response intercept(Chain chain) throws IOException {
//做一些其他的準備工作
response = realChain.proceed(request, transmitter, null);
//處理response
return response;
}
當調用的 proceed 方法的時候,我們就會調用到 realChain.proceed 方法,這樣 index + 1,就會執行到下一個 Interceptor 的 intercept 方法,也就是 BridgeInterceptor 的 intercept 方法。我畫一個圖示意。
BridgeInterceptor implements Interceptor
CacheInterceptor implements Interceptor
ConnectInterceptor implements Interceptor
建立TCP連接。
OkHttp的主要用途是封裝了網絡請求,讓我們更簡單的操作網絡請求。
- 使用線程池提高了性能。
- 然後就是攔截器部分,使用了責任鏈模式。熟悉下每個攔截器的作用。