前言
OkHttp可以說是最主流的網(wǎng)絡(luò)請求框架了,很多項目是直接使用Retrofit 2.0提供的接口進行網(wǎng)絡(luò)請求,Retrofit 是一個 RESTful 的 HTTP 網(wǎng)絡(luò)請求框架的封裝。想了解Retrofit請移步Retrofit 2.0 源碼分析,retrofit是負責(zé)接口封裝,okhttp才是真正的網(wǎng)絡(luò)請求,今天我們就一起探究整個okhttp請求的過程,本章節(jié)并不會著重講怎么使用,主要閱讀源碼了解內(nèi)部的部分機制以及一些核心類的作用。
初始化OkHttpClient
OkHttpClient mOkHttpClient = new OkHttpClient();
OkHttpClient實例是通過建造者模式通過Builder類進行創(chuàng)建的
public OkHttpClient() {
this(new Builder());
}
我們看一下builder初始化了哪些參數(shù)
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
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;
}
構(gòu)造一個Request,也是通過建造者模式創(chuàng)建的
Request request = new Request.Builder()
.url(url)
.build();
Request類是HTTP請求,它攜帶了請求地址、請求方法、請求頭部、請求體以及其他信息。它也是通過Builder模式創(chuàng)建的。
private Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tag = builder.tag != null ? builder.tag : this;
}
開始請求
Response response = mOkHttpClient.newCall(request).execute();
看一下 OkHttpClient.newCall(request),做了什么,RealCall類實現(xiàn)了Call接口,下面展示RealCall()方法的代碼
protected RealCall(OkHttpClient client, Request originalRequest) {
this.client = client;
this.originalRequest = originalRequest;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
}
接著是RealCall的execute()方法。execute()方法是同步方法,即一直等待http請求, 直到返回了響應(yīng). 在這之間會阻塞進程, 所以通過同步方法不能在Android的主線程中執(zhí)行, 否則會報錯。
OKHttp提供了execute(同步方法)和enqueue(異步方法),下面我們先看看execute(同步方法)
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
execute()方法,首先判斷是否已執(zhí)行過,如果已經(jīng)執(zhí)行過,則拋出異常信息,也就是說一次Call實例只能調(diào)用一次execute()方法,和我們之前說的一樣。
如果未執(zhí)行,則調(diào)用Dispatcher類的executed()方法將該Call加入到一個雙端隊列中
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();//雙端隊列
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
接著調(diào)用getResponseWithInterceptorChain()方法返回Response對象,最后finally中,調(diào)用Dispatcher的finished()方法,在從已經(jīng)執(zhí)行的雙端隊列中移除本次Call。
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();
}
}
通過上面分析,真正發(fā)出網(wǎng)絡(luò)請求,返回結(jié)果應(yīng)該是getResponseWithInterceptorChain()方法,那么接下來,主要看看這個方法
private 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
該方法是組裝各種攔截器為一個攔截器鏈,最后調(diào)用RealInterceptorChain的proceed()方法,來處理這個請求
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpStream, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream,
Connection connection) 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.httpStream != null && !sameConnection(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.httpStream != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpStream, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpStream != 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");
}
return response;
}
攔截器Interceptor和攔截器鏈Chain都是接口
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
下面用一張流程圖來說明攔截器鏈遞歸從攔截器中返回Response

下面再看看enqueue()方法(異步方法),指在另外的工作線程中執(zhí)行http請求, 請求時不會阻塞當(dāng)前的線程, 所以可以在Android主線程中使用。
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
首先都校驗這個Call是否已經(jīng)被執(zhí)行,如果執(zhí)行過,就報異常。如果為執(zhí)行,則調(diào)用Dispatcher分發(fā)器的enqueue()方法。看下AsyncCall這個類,
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@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);
}
}
}
NamedRunnable是實現(xiàn)了Runnable接口,AsyncCall–實際上是一個Runnable,在run()方法中調(diào)用了execute()方法,在該方法中調(diào)用getResponseWithInterceptorChain()
Response response = getResponseWithInterceptorChain();
拿到請求結(jié)果,接下來看一下client.dispatcher().finished(this)做了什么
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()方法先從runningAsyncCalls(異步請求隊列)刪除已經(jīng)執(zhí)行的異步請求,然后接著調(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.
}
}
首先runningAsyncCalls(異步請求隊列) readyAsyncCalls和異步調(diào)用準(zhǔn)備任務(wù))兩部判斷,接著循環(huán)readyAsyncCalls),將call加入到runningAsyncCalls中,并在readyAsyncCalls刪除掉該call,接著線程池執(zhí)行call
繼續(xù)看Dispatcher分發(fā)器的enqueue()方法
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
如果runningAsyncCalls的大小小于最大請求數(shù)量(最大線程數(shù)量、并發(fā)數(shù)量)并且call小于最大主機請求限
制,那么將call 加入到runningAsyncCalls中,接著線程池執(zhí)行call;否則,將call加入到readyAsyncCalls(異步調(diào)用準(zhǔn)備任務(wù))。
PS: runningCallsForHost()方法,循環(huán)判斷cal的host和runningAsyncCalls的中的call的host相同的數(shù)量。同一請求是否超過想過請求同時存在的最大值
private int runningCallsForHost(AsyncCall call) {
int result = 0;
for (AsyncCall c : runningAsyncCalls) {
if (c.host().equals(call.host())) result++;
}
return result;
}
接下來看一下Dispatcher類,這個是核心類,Dispatcher是異步請求的策略
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
/** Executes calls. Created lazily. */
private ExecutorService executorService;
/** 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<>();
...
}
int maxRequests = 64: 最大并發(fā)請求數(shù)為64
int maxRequestsPerHost = 5: 每個主機最大請求數(shù)為5
Runnable idleCallback:Runnable對象,在刪除任務(wù)時執(zhí)行
ExecutorService executorService:消費者池(也就是線程池)
Deque<AsyncCall> readyAsyncCalls:緩存,異步調(diào)用準(zhǔn)備執(zhí)行任務(wù)
Deque<AsyncCall> runningAsyncCalls:正在運行的異步任務(wù),包含取消尚未完成的調(diào)用
Deque<RealCall> runningSyncCalls: 正在運行的同步任務(wù),包含取消尚未完成的調(diào)用
最后看一下整個請求的流程圖

整個OkHttp源碼分析請求過程就結(jié)束了
總結(jié)
基本上 OkHttp 的請求響應(yīng)的流程就講完了,內(nèi)容有點多。本章節(jié)只是分析了主要部分的源碼,先對整個結(jié)構(gòu)要有一個系統(tǒng)性的了解,還有很多細節(jié)沒有展開,比如連接池、緩存策略等等一些機制的實現(xiàn),有興趣可以單獨深度去了解。