OKHttp 3.14.X源碼架構
如何使用OKHttp
這裏以非Kotlin版本介紹
- 首先在
build.gradle
中添加組件:
implementation 'com.squareup.okhttp3:okhttp:3.14.2'
- 在MainActivity中調用OkHttp的API:
//注意這裏,一般我們用單例,Okhttp官方描述如果不用單例,線程管理等都失效了,浪費開銷
/*Http performs best when you create a single {@code OkHttpClient} instance and reuse it for
* all of your HTTP calls. This is because each client holds its own connection pool and thread
* pools. Reusing connections and threads reduces latency and saves memory. Conversely, creating a
* client for each request wastes resources on idle pools.
*/
OkHttpClient client = new OkHttpClient();
String run(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
OKHttp工作流程圖
OKHttpClient的創建
通過okhttp源碼分析,直接創建的 OkHttpClient對象並且默認構造builder對象進行初始化
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
public OkHttpClient() {
this(new Builder());
}
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
...
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
}
}
Request的發出
一般如下:
Request request = new Request.Builder().url("url").build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
初始化構建者模式和請求對象,並且用URL替換Web套接字URL。
public final class Request {
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
public Builder url(String url) {
......
// Silently replace web socket URLs with HTTP URLs.
if (url.regionMatches(true, 0, "ws:", 0, 3)) {
url = "http:" + url.substring(3);
} else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
url = "https:" + url.substring(4);
}
HttpUrl parsed = HttpUrl.parse(url);
......
return url(parsed);
}
public Request build() {
......
return new Request(this);
}
}
主裏主要是調用了newCall
方法,我們跟進去看看:
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
@Override
public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
}
發現去new RealCall
了,我們跟到RealCall
看看:
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
}
可以看到只是初始化一些成員變量,真正的調用是RealCall
裏面的enqueue(添加到隊列)/execute(立即執行)
方法,我們看看:
void enqueue(AsyncCall call) {
synchronized (this) {
/** Ready async calls in the order they'll be run. */
//private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
// readyAsyncCalls是一個雙端隊列,把該call加入到準備的隊列裏
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();
}
上面不難發現最終調用了promoteAndExecute()
,我們跟進去看看:
/**
* 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) {
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity. // 最大的線程請求的時候,不再添加, maxRequests默認值是:64
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity. // 最大的DNS解析爲:5
i.remove();
asyncCall.callsPerHost().incrementAndGet();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
// 循環執行
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
有一個問題,enqueue
是拿到Reponse的? 它和execute
區別?
帶着問題,我們可以在RealCall
中可以發現 final class AsyncCall extends NamedRunnable
這個NamedRunnable
是什麼?
/**
* 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);
}
@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();
}
根據源碼發現它原來是一個runable
,並且抽象了execute
,所以execute
就是enqueue
去執行的核心方法,那麼我就可以看到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);
}
} finally {
client.dispatcher().finished(this);
}
}
實際上跟execute
方法一樣,都是調用了getResponseWithInterceptorChain
,跟進去看看:
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());// 1.添加自定義的攔截器
interceptors.add(new RetryAndFollowUpInterceptor(client));// 2.重試攔截
interceptors.add(new BridgeInterceptor(client.cookieJar())); // 3.Build一個適配的Request
interceptors.add(new CacheInterceptor(client.internalCache()));// 4.添加緩存攔截器
interceptors.add(new ConnectInterceptor(client)); // 5.ConnectInterceptor驗證Get請求
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors()); // 6.非Websocket下創建的自定義網絡攔截器
}
interceptors.add(new CallServerInterceptor(forWebSocket)); // 7. 真實的IO訪問,使用了OKIO庫去實現的
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
.....
return response;
}
從上面的設計模式可以看出來OKHttp使用了責任鏈
的設計模式. 至此流程已經完畢. 下面學習一些優秀的細節.