OkHttp源碼分析
在現(xiàn)在的Android開(kāi)發(fā)中,請(qǐng)求網(wǎng)絡(luò)獲取數(shù)據(jù)基本上成了我們的標(biāo)配。在早期的Android開(kāi)發(fā)中會(huì)有人使用HttpClient、HttpUrlConnection或者Volley等網(wǎng)絡(luò)請(qǐng)求方式,但對(duì)于如今(2018年)而言,絕大多數(shù)的開(kāi)發(fā)者都會(huì)使用OkHttp+Retrofit+RxJava進(jìn)行網(wǎng)絡(luò)請(qǐng)求,而對(duì)于這三者而言,實(shí)際請(qǐng)求網(wǎng)絡(luò)的框架是OkHttp,所以O(shè)kHttp的重要性不言而喻。
OkHttp的基本用法
//創(chuàng)建OkHttpClient對(duì)象
OkHttpClient client = new OkHttpClient();
String run(String url) throws IOException {
//創(chuàng)建Request請(qǐng)求對(duì)象
Request request = new Request.Builder()
.url(url)
.build();
//創(chuàng)建Call對(duì)象,并執(zhí)行同步獲取網(wǎng)絡(luò)數(shù)據(jù)
Response response = client.newCall(request).execute();
return response.body().string();
}
使用OkHttp基本是以下四步:
- 創(chuàng)建OkHttpClient對(duì)象
- 創(chuàng)建Request請(qǐng)求對(duì)象
- 創(chuàng)建Call對(duì)象
- 同步請(qǐng)求調(diào)用call.execute();異步請(qǐng)求調(diào)用call.enqueue(callback)
接下來(lái)我會(huì)對(duì)這四步進(jìn)行詳細(xì)的說(shuō)明。
創(chuàng)建OkHttpClient對(duì)象
通常來(lái)說(shuō),我們使用OkHttp并不會(huì)直接通過(guò)new OkHttpClient()來(lái)創(chuàng)建出一個(gè)OkHttpClient。一般來(lái)說(shuō),我們會(huì)對(duì)這個(gè)OkHttpClient做一些配置,比如:
OkHttpClient.Builder().connectTimeout(
DEFAULT_MILLISECONDS, TimeUnit.SECONDS).readTimeout(
DEFAULT_MILLISECONDS, TimeUnit.SECONDS).addInterceptor { chain ->
val builder = chain.request().newBuilder()
headerMap?.forEach {
builder.addHeader(it.key, it.value)
}
val request = builder.build()
chain.proceed(request)
}.addInterceptor(httpLoggingInterceptor).build()
上面是一段使用Kotlin代碼創(chuàng)建OkHttpClient的過(guò)程,很明顯,OkHttpClient內(nèi)部是使用了 Builder 模式,好處很明顯: 我們?cè)趧?chuàng)建對(duì)象的同時(shí)可以自由的配置我們需要的參數(shù) 。我們簡(jiǎn)單看一下OkHttpClient內(nèi)部類(lèi)Builder中的構(gòu)造方法,看一下OkHttpClient內(nèi)部都可以做哪些配置:
public Builder() {
//默認(rèn)的分發(fā)器
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
//事件監(jiān)聽(tīng)工廠
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;
//默認(rèn)連接超時(shí)10s
connectTimeout = 10_000;
//默認(rèn)讀取超時(shí)10s
readTimeout = 10_000;
//默認(rèn)寫(xiě)入超時(shí)10s
writeTimeout = 10_000;
pingInterval = 0;
}
上面的代碼中我們非常熟悉的就是連接超時(shí)、讀取超時(shí)、寫(xiě)入超時(shí),它們的默認(rèn)事件都是10s,其實(shí)這也提醒我們,如果我們想要設(shè)置的超時(shí)時(shí)間也是10s的話(huà),完全沒(méi)有必要重復(fù)進(jìn)行配置,其實(shí)我的建議也是不需要配置,直接使用默認(rèn)的就好。值得注意的是 Dispatcher 這個(gè)類(lèi),這是一個(gè)網(wǎng)絡(luò)請(qǐng)求的分發(fā)器,主要作用是在同步,異步網(wǎng)絡(luò)請(qǐng)求時(shí)會(huì)做一些不同的分發(fā)處理,我們先有個(gè)印象即可, Dispatcher 會(huì)在之后詳細(xì)的分析。
可能細(xì)心的小伙伴這時(shí)候會(huì)說(shuō)了:我平時(shí)會(huì)對(duì)OkHttpClient加上一些interceptor來(lái)攔截網(wǎng)絡(luò)請(qǐng)求,比方說(shuō)在請(qǐng)求之前加上token等請(qǐng)求頭之類(lèi)的,上面這段代碼為什么沒(méi)有攔截器相關(guān)的變量呢?
沒(méi)錯(cuò),OkHttpClient中的Builder類(lèi)內(nèi)部確實(shí)是有攔截器相關(guān)成員變量,只不過(guò)沒(méi)寫(xiě)在Builder的構(gòu)造方法內(nèi):
public static final class Builder {
//省略無(wú)關(guān)代碼......
final List<Interceptor> interceptors = new ArrayList<>();
final List<Interceptor> networkInterceptors = new ArrayList<>();
//省略無(wú)關(guān)代碼......
}
我們平常添加的interceptor就存放在interceptors這個(gè)ArrayList中。OkHttpClient對(duì)象的配置創(chuàng)建不是什么難以理解的點(diǎn),接下來(lái)我們看Request對(duì)象的創(chuàng)建。
創(chuàng)建Request請(qǐng)求對(duì)象
為什么要?jiǎng)?chuàng)建Request對(duì)象,很簡(jiǎn)單,我們請(qǐng)求網(wǎng)絡(luò)需要一些必要的參數(shù),比如url,請(qǐng)求方式是get或者post等等信息。而Request這個(gè)類(lèi)就是對(duì)這些網(wǎng)絡(luò)請(qǐng)求參數(shù)的統(tǒng)一封裝。看一下代碼就一目了然了:
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
final Object tag;
private volatile CacheControl cacheControl; // Lazily initialized.
//省略無(wú)關(guān)代碼......
}
相信大家都能看明白,這個(gè)Request類(lèi)中封裝了url、請(qǐng)求方式、請(qǐng)求頭、請(qǐng)求體等等網(wǎng)絡(luò)請(qǐng)求相關(guān)的信息。Request里面也是一個(gè)Builder模式,這里就不贅述了。
創(chuàng)建Call對(duì)象
Call對(duì)象我們可以這樣理解:Call對(duì)象是對(duì) 一次 網(wǎng)絡(luò)請(qǐng)求的封裝。注意這個(gè)關(guān)鍵字: 一次 ,熟悉OkHttp的同學(xué)應(yīng)該都知道,一個(gè)Call對(duì)象只能被執(zhí)行一次,不論是同步execute還是異步的enqueue,那么這個(gè)只能執(zhí)行一次的特性是如何保證的呢?我們來(lái)看代碼:
@Override public Call newCall(Request request) {
//實(shí)際上是通過(guò) RealCall.newRealCall 來(lái)獲取Call對(duì)象
return RealCall.newRealCall(this, request, false /* for web socket */);
}
上面的代碼能看到OkHttpClient的newCall實(shí)際上是通過(guò)RealCall.newRealCall(this, request, false /* for web socket */)來(lái)獲得的,我們來(lái)看一下這個(gè)RealCall:
final class RealCall implements Call {
final OkHttpClient client;
//錯(cuò)誤重試與重定向攔截器
final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
//監(jiān)聽(tīng)OkHttp網(wǎng)絡(luò)請(qǐng)求各個(gè)階段的事件監(jiān)聽(tīng)器
private EventListener eventListener;
final Request originalRequest;
final boolean forWebSocket;
//判斷Call對(duì)象是否被執(zhí)行過(guò)的標(biāo)志變量
private boolean executed;
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Call只是一個(gè)接口,我們實(shí)際創(chuàng)建的是Call的實(shí)現(xiàn)類(lèi)RealCall的對(duì)象
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
Override public Response execute() throws IOException {
//確保線(xiàn)程安全的情況下通過(guò)executed來(lái)保證每個(gè)Call只被執(zhí)行一次
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//省略無(wú)關(guān)代碼......
}
@Override public void enqueue(Callback responseCallback) {
/確保線(xiàn)程安全的情況下通過(guò)executed來(lái)保證每個(gè)Call只被執(zhí)行一次
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//省略無(wú)關(guān)代碼
}
//省略無(wú)關(guān)代碼......
}
我們可以看到,Call只是一個(gè)接口,我們創(chuàng)建的實(shí)際上是RealCall對(duì)象。在RealCall中存在一個(gè) execute 的成員變量,在execute()和enqueue(Callback responseCallback) 方法中都是通過(guò) execute 來(lái)確保每個(gè)RealCall對(duì)象只會(huì)被執(zhí)行一次。
創(chuàng)建Call對(duì)象的過(guò)程其實(shí)也是很簡(jiǎn)單的,麻煩的地方在最后一步: **execute()和enqueue(Callback responseCallback) **
同步請(qǐng)求與異步請(qǐng)求
前三步非常簡(jiǎn)單,我們可以知道并沒(méi)有涉及網(wǎng)絡(luò)的請(qǐng)求,所以核心肯定是在這關(guān)鍵的第四步。
同步請(qǐng)求execute()和異步請(qǐng)求enqueue(Callback responseCallback)
先說(shuō)同步請(qǐng)求,看代碼:
@Override public Response execute() throws IOException {
//通過(guò)executed確保每個(gè)Call對(duì)象只會(huì)被執(zhí)行一次
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
//網(wǎng)絡(luò)請(qǐng)求開(kāi)始的回調(diào)
eventListener.callStart(this);
try {
//調(diào)用分發(fā)器的executed(this)方法
client.dispatcher().executed(this);
//真實(shí)的網(wǎng)絡(luò)請(qǐng)求是在這里處理的
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
//網(wǎng)絡(luò)請(qǐng)求失敗的回調(diào)
eventListener.callFailed(this, e);
throw e;
} finally {
//網(wǎng)絡(luò)請(qǐng)求結(jié)束
client.dispatcher().finished(this);
}
}
execute() 方法中首先通過(guò)executed確保每個(gè)Call對(duì)象只會(huì)被執(zhí)行一次,之后調(diào)用了eventListener.callStart(this);來(lái)執(zhí)行網(wǎng)絡(luò)請(qǐng)求開(kāi)始的回調(diào)。接下來(lái)調(diào)用了client.dispatcher().executed(this),那么這句代碼具體是做了什么呢:
public Dispatcher dispatcher() {
//返回了一個(gè)OkHttpClient內(nèi)部的dispather分發(fā)器
return dispatcher;
}
這句代碼首先返回一個(gè) dispatcher ,這個(gè)分發(fā)器我們?cè)谏厦嬉蔡岬竭^(guò),這是一個(gè)比較重要的概念,來(lái)看一下這個(gè)分發(fā)器:
public final class Dispatcher {
//最大請(qǐng)求數(shù)
private int maxRequests = 64;
//每個(gè)host的最大請(qǐng)求數(shù)
private int maxRequestsPerHost = 5;
//網(wǎng)絡(luò)請(qǐng)求處于空閑時(shí)的回調(diào)
private @Nullable Runnable idleCallback;
//線(xiàn)程池的實(shí)現(xiàn)
private @Nullable ExecutorService executorService;
//就緒等待網(wǎng)絡(luò)請(qǐng)求的異步隊(duì)列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在執(zhí)行網(wǎng)絡(luò)請(qǐng)求的異步隊(duì)列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在執(zhí)行網(wǎng)絡(luò)請(qǐng)求的同步隊(duì)列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
//忽略無(wú)關(guān)代碼......
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
synchronized void executed(RealCall call) {
//將call對(duì)象加入網(wǎng)絡(luò)請(qǐng)求的同步隊(duì)列中
runningSyncCalls.add(call);
}
//忽略無(wú)關(guān)代碼......
}
可以看到 Dispatcher 這個(gè)分發(fā)器類(lèi)內(nèi)部定義了很多的成員變量:maxRequests 最大請(qǐng)求個(gè)數(shù),默認(rèn)值是64; maxRequestsPerHost 每個(gè)host的最大請(qǐng)求個(gè)數(shù),這個(gè)host是什么?舉個(gè)栗子,一個(gè)URL為 http://gank.io/api ,那么host就是 http://gank.io/ 相當(dāng)于baseUrl。 ** idleCallback** 這是一個(gè)空閑狀態(tài)時(shí)的回調(diào),當(dāng)我們的所有的網(wǎng)絡(luò)請(qǐng)求隊(duì)列為空時(shí)會(huì)執(zhí)行。 executorService 這是一個(gè)線(xiàn)程池,主要是為了高效執(zhí)行異步的網(wǎng)絡(luò)請(qǐng)求而創(chuàng)建的線(xiàn)程池,之后會(huì)再次提到它。接下來(lái)就是比較重要的三個(gè)隊(duì)列:
- readyAsyncCalls -> 在就緒等待的異步Call隊(duì)列
- runningAsyncCalls -> 正在執(zhí)行的異步Call隊(duì)列
- runningSyncCalls -> 正在執(zhí)行的同步Call隊(duì)列
對(duì)于這三個(gè)隊(duì)列來(lái)說(shuō),執(zhí)行同步請(qǐng)求的Call對(duì)象會(huì)加入到runningSyncCalls中;執(zhí)行異步請(qǐng)求的Call對(duì)象會(huì)加入到readyAsyncCalls或者runningAsyncCalls中,那么什么時(shí)候加入到等待隊(duì)列,什么時(shí)候加入到執(zhí)行隊(duì)列呢?簡(jiǎn)單的說(shuō),如果執(zhí)行異步網(wǎng)絡(luò)請(qǐng)求的線(xiàn)程池很忙,異步請(qǐng)求的Call對(duì)象會(huì)加入到等待隊(duì)列;反之則加入到執(zhí)行隊(duì)列。那么這個(gè)忙于不忙的標(biāo)準(zhǔn)是什么呢?很簡(jiǎn)單,在enqueue方法中有runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost一個(gè)判斷的標(biāo)準(zhǔn),即正在執(zhí)行的異步隊(duì)列中Call對(duì)象個(gè)數(shù)小于maxRequests(64)并且執(zhí)行隊(duì)列中的同一個(gè)host對(duì)應(yīng)的Call對(duì)象個(gè)數(shù)小于maxRequestsPerHost(5)的時(shí)候。
說(shuō)完了 Dispatcher 關(guān)鍵的成員變量,我們來(lái)看一下它的 **executed(RealCall call) ** 方法:
synchronized void executed(RealCall call) {
//將call對(duì)象加入網(wǎng)絡(luò)請(qǐng)求的同步隊(duì)列中
runningSyncCalls.add(call);
}
這是一個(gè)synchronized修飾的方法,為了確保線(xiàn)程安全。Dispatcher中的executed(RealCall call)方法及其簡(jiǎn)單,就是把Call對(duì)象加入到同步Call隊(duì)列中。對(duì),你沒(méi)有看錯(cuò),它確實(shí)就只有這一行代碼,沒(méi)什么復(fù)雜的操作。
說(shuō)完了 Dispatcher 中的同步方法,我們?cè)賮?lái)看一下異步:
synchronized void enqueue(AsyncCall call) {
//判斷Call對(duì)象應(yīng)該添加到等待隊(duì)列還是執(zhí)行隊(duì)列
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//加入執(zhí)行隊(duì)列
runningAsyncCalls.add(call);
//線(xiàn)程池開(kāi)啟線(xiàn)程執(zhí)行異步網(wǎng)絡(luò)請(qǐng)求
executorService().execute(call);
} else {
//加入等待隊(duì)列
readyAsyncCalls.add(call);
}
}
和同步方法相比,異步方法中的內(nèi)容要稍微多一點(diǎn)。首先是判斷Call對(duì)象應(yīng)該添加到等待隊(duì)列還是執(zhí)行隊(duì)列,這個(gè)判斷上面已經(jīng)說(shuō)過(guò)。加入執(zhí)行隊(duì)列后,開(kāi)啟線(xiàn)程池并執(zhí)行Call對(duì)象。這里需要注意的是異步請(qǐng)求時(shí)的Call對(duì)象和同步請(qǐng)求時(shí)不一樣,會(huì)轉(zhuǎn)換成一個(gè) AsyncCall 對(duì)象,這個(gè) AsyncCall 實(shí)際上是一個(gè) NamedRunnable ,那既然是一個(gè) Runnable ,我們肯定要看一下它的execute()方法:
@Override protected void execute() {
boolean signalledCallback = false;
try {
//核心的請(qǐng)求網(wǎng)絡(luò)方法
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);
}
}
}
其實(shí)整段代碼看似非常多,核心就只有Response response = getResponseWithInterceptorChain()這一句:通過(guò)攔截器鏈獲取網(wǎng)絡(luò)返回結(jié)果。其實(shí)不止是異步請(qǐng)求,同步請(qǐng)求的核心也是這一行代碼。我們繼續(xù)看一下RealCall中的execute方法:
@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);
//跟異步請(qǐng)求一樣,核心也是通過(guò)攔截器鏈來(lái)獲取網(wǎng)絡(luò)數(shù)據(jù)
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);
}
}
很明顯,在client.dispatcher().executed(this)將Call對(duì)象加入同步請(qǐng)求隊(duì)列中之后,同樣調(diào)用的是Response result = getResponseWithInterceptorChain()。明白了嗎,不論是在同步請(qǐng)求或者是異步請(qǐng)求,最終獲取網(wǎng)絡(luò)數(shù)據(jù)的核心處理都是一致的:getResponseWithInterceptorChain() 。
接下來(lái)我們來(lái)分析這個(gè)在OkHttp中非常核心的方法:
Response getResponseWithInterceptorChain() throws IOException {
//創(chuàng)建存放攔截器的list
List<Interceptor> interceptors = new ArrayList<>();
//攔截器列表加入我們配置OkHttpClient時(shí)添加的攔截器
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) {
//如果不是針對(duì)WebSocket的網(wǎng)絡(luò)訪問(wèn),加入網(wǎng)絡(luò)攔截器
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
//創(chuàng)建攔截器鏈
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//執(zhí)行攔截器鏈
return chain.proceed(originalRequest);
}
在這個(gè)方法中首先創(chuàng)建了一個(gè)ArrayList,用來(lái)存放所有的攔截器。從上到下可以看到,一共是添加了7中不同的攔截器:
- client.interceptors() -> 我們自己添加的請(qǐng)求攔截器,通常是做一些添加統(tǒng)一的token之類(lèi)操作
- retryAndFollowUpInterceptor -> 主要負(fù)責(zé)錯(cuò)誤重試和請(qǐng)求重定向
- BridgeInterceptor -> 負(fù)責(zé)添加網(wǎng)絡(luò)請(qǐng)求相關(guān)的必要的一些請(qǐng)求頭,比如Content-Type、Content-Length、Transfer-Encoding、User-Agent等等
- CacheInterceptor -> 負(fù)責(zé)處理緩存相關(guān)操作
- ConnectInterceptor -> 負(fù)責(zé)與服務(wù)器進(jìn)行連接的操作
- networkInterceptors -> 同樣是我們可以添加的攔截器的一種,它與client.interceptors() 不同的是二者攔截的位置不一樣。
- CallServerInterceptor -> 在這個(gè)攔截器中才會(huì)進(jìn)行真實(shí)的網(wǎng)絡(luò)請(qǐng)求
在添加完各種攔截器后,創(chuàng)建了一個(gè)攔截器鏈,然后執(zhí)行了攔截器鏈的proceed方法,我們來(lái)看一下這個(gè)proceed方法:
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
這個(gè)方法調(diào)用的是 RealInterceptorChain 內(nèi)部的另一個(gè)proceed方法,再跟進(jìn)去看一下:
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//忽略無(wú)關(guān)代碼......
// 獲取攔截鏈中的下一個(gè)攔截器
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
//通過(guò)調(diào)用攔截器的intercept方法獲取網(wǎng)絡(luò)數(shù)據(jù)
Response response = interceptor.intercept(next);
//忽略無(wú)關(guān)代碼......
return response;
}
這個(gè)方法中主要分為兩步:獲取攔截鏈中的下一個(gè)攔截器,然后調(diào)用這個(gè)攔截器的 intercept(next) 方法,在構(gòu)建OkHttpClietn時(shí)添加過(guò)interceptor的同學(xué)應(yīng)該都比較清楚,在intercept()方法中我們必須要存在chain.proceed(request)這樣一句代碼。類(lèi)似于這樣:
OkHttpClient.Builder().connectTimeout(
DEFAULT_MILLISECONDS, TimeUnit.SECONDS).readTimeout(
DEFAULT_MILLISECONDS, TimeUnit.SECONDS).addInterceptor { chain ->
val builder = chain.request().newBuilder()
headerMap?.forEach {
builder.addHeader(it.key, it.value)
}
val request = builder.build()
//將攔截器鏈執(zhí)行下去
chain.proceed(request)
}.addInterceptor(httpLoggingInterceptor).build()
每個(gè)攔截器內(nèi)部的intercept方法內(nèi)部必須存在chain.proceed(request),同樣,OkHttp提供的攔截器的intercept方法內(nèi)部都必須存在chain.proceed(request)這句代碼,除了最后一個(gè)攔截器CallServerInterceptor。
整個(gè)邏輯是不是有些混亂,沒(méi)關(guān)系,我們來(lái)整理一下。
- getResponseWithInterceptorChain()方法通過(guò)調(diào)用chain.proceed(originalRequest)開(kāi)啟攔截鏈。
- 在RealInterceptorChain的proceed(request)方法中會(huì)調(diào)用下一個(gè)攔截器中的intercept(chain)方法
- 在攔截器中的intercept(chain)中會(huì)調(diào)用chain.proceed(request)
上面是一個(gè)循環(huán)調(diào)用,由于每次獲取的攔截器是攔截器列表中的下一個(gè)攔截器,所以實(shí)現(xiàn)了順序調(diào)用攔截器列表中的每個(gè)不同的攔截器的攔截方法。因?yàn)樽詈笠粋€(gè)攔截器并沒(méi)有調(diào)用chain.proceed(request),所以能夠結(jié)束循環(huán)調(diào)用。
再來(lái)張圖,加深大家對(duì)攔截器鏈的理解:

看完這張圖,小伙伴們應(yīng)該會(huì)對(duì)整個(gè)攔截器鏈的運(yùn)作流程有一定的了解。到此為止,OkHttp的源碼分析就告一段落了,具體每個(gè)攔截器中的實(shí)現(xiàn)細(xì)節(jié),大家如果有興趣的話(huà)可以自己去深入了解一下,我這里就不再贅述了。