1.okhttp源碼分析(一)——基本流程(超詳細(xì))
2.okhttp源碼分析(二)——RetryAndFollowUpInterceptor過濾器
3.okhttp源碼分析(三)——CacheInterceptor過濾器
4.okhttp源碼分析(四)——ConnectInterceptor過濾器
5.okhttp源碼分析(五)——CallServerInterceptor過濾器
前言
最近算是入了源碼的坑了,什么東西總想按住ctrl看看源碼的模樣,這段時(shí)間在研究okhttp的源碼,發(fā)現(xiàn)okhttp的源碼完全不是簡(jiǎn)簡(jiǎn)單單的幾天就可以啃下來的,那就一步一步來吧。
這篇博客主要是從okhttp的總體流程分析源碼的執(zhí)行過程,對(duì)okhttp源碼有大體上的理解,從全局上看出okhttp的設(shè)計(jì)思想。
分析
1.OkHttpClient
既然是流程分析,使用過okhttp的都了解,首先需要初始化一個(gè)OkHttpClient對(duì)象。OkHttp支持兩種構(gòu)造方式
1.默認(rèn)方式
public OkHttpClient() {
this(new Builder());
}
可以看到這種方式,不需要配置任何參數(shù),也就是說基本參數(shù)都是默認(rèn)的,調(diào)用的是下面的構(gòu)造函數(shù)。
OkHttpClient(Builder builder) {...}
2.builder模式,通過Builder配置參數(shù),最后通過builder()方法返回一個(gè)OkHttpClient實(shí)例。
public OkHttpClient build() {
return new OkHttpClient(this);
}
OkHttpClient基本上就這樣分析完了,里面的細(xì)節(jié)基本上就是用于初始化參數(shù)和設(shè)置參數(shù)的方法。所以也必要將大量的代碼放上來占內(nèi)容。。。,這里另外提一點(diǎn),從OkHttpClient中可以看出什么設(shè)計(jì)模式哪?
1.builder模式
2.外觀模式
2.Request
構(gòu)建完OkHttpClient后就需要構(gòu)建一個(gè)Request對(duì)象,查看Request的源碼你會(huì)發(fā)現(xiàn),你找不多public的構(gòu)造函數(shù),唯一的一個(gè)構(gòu)造函數(shù)是這樣的。
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;
}
這意味著什么,當(dāng)然我們構(gòu)建一個(gè)request需要用builder模式進(jìn)行構(gòu)建,那么就看一下builder的源碼。
public Builder newBuilder() {
return new Builder(this);
}
//builder===================
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
Builder(Request request) {
this.url = request.url;
this.method = request.method;
this.body = request.body;
this.tag = request.tag;
this.headers = request.headers.newBuilder();
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
其實(shí)忽略其他的源碼,既然這篇博客只是為了從總體流程上分析OkHttp的源碼,所以我們主要著重流程源碼上的分析。從上面的源碼我們會(huì)發(fā)現(xiàn),request的構(gòu)建也是基于builder模式。
3.異步請(qǐng)求
這里注意一下,這里分析區(qū)分一下同步請(qǐng)求和異步請(qǐng)求,但其實(shí)實(shí)質(zhì)的執(zhí)行流程除了異步外,基本都是一致的。
構(gòu)建完Request后,我們就需要構(gòu)建一個(gè)Call,一般都是這樣的Call call = mOkHttpClient.newCall(request);那么我們就返回OkHttpClient的源碼看看。
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
//工廠模式
return RealCall.newRealCall(this, request, false /* for web socket */);
}
可以看到,這里實(shí)質(zhì)上調(diào)用的是RealCall中的newRealCall方法,但是這里需要注意一點(diǎn),那就是方法前面的@Override注解,看到這個(gè)注解我們就要意識(shí)到,這個(gè)方法不是繼承就是實(shí)現(xiàn)接口。
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {...}
可以看到OkhttpClient實(shí)現(xiàn)了Call.Factory接口。
//Call.java
interface Factory {
Call newCall(Request request);
}
從接口源碼我們也可以看出,這個(gè)接口其實(shí)并不復(fù)雜,僅僅是定義一個(gè)newCall用于創(chuàng)建Call的方法,這里其實(shí)用到了工廠模式的思想,將構(gòu)建的細(xì)節(jié)交給具體實(shí)現(xiàn),頂層只需要拿到Call對(duì)象即可。
回到主流程,我們繼續(xù)看RealCall中的newRealCall方法。
final class RealCall implements Call {
...
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實(shí)現(xiàn)了Call接口,newRealCall這是一個(gè)靜態(tài)方法,new了一個(gè)RealCall對(duì)象,并創(chuàng)建了一個(gè)eventListener對(duì)象,從名字也可以看出,這個(gè)是用來監(jiān)聽事件流程,并且從構(gòu)建方法我們也可以看出,使用了工廠模式
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
//默認(rèn)創(chuàng)建一個(gè)retryAndFollowUpInterceptor過濾器
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
重點(diǎn)來了,可以看到,在RealCall的構(gòu)造函數(shù)中,除了基本的賦值外,默認(rèn)創(chuàng)建一個(gè)retryAndFollowUpInterceptor過濾器,過濾器可以說是OkHttp的巨大亮點(diǎn),后續(xù)的文章我會(huì)詳細(xì)分析一些過濾器吧(能力有限,盡量全看看)。
現(xiàn)在Call創(chuàng)建完了,一般就到最后一個(gè)步驟了,將請(qǐng)求加入調(diào)度,一般的代碼是這樣的。
//請(qǐng)求加入調(diào)度
call.enqueue(new Callback()
{
@Override
public void onFailure(Request request, IOException e)
{
}
@Override
public void onResponse(final Response response) throws IOException
{
//String htmlStr = response.body().string();
}
});
可以看到這里調(diào)用了call的enqueue方法,既然這里的call->RealCall,所以我們看一下RealCall的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));
}
1.首先利用synchronized加入了對(duì)象鎖,防止多線程同時(shí)調(diào)用,這里先判斷一下executed是否為true判斷當(dāng)前call是否被執(zhí)行了,如果為ture,則拋出異常,沒有則設(shè)置為true。
2.captureCallStackTrace()
private void captureCallStackTrace() {
Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
}
可以看到這里大體上可以理解為為retryAndFollowUpInterceptor加入了一個(gè)用于追蹤堆棧信息的callStackTrace,后面有時(shí)間再詳細(xì)分析一下這部分吧,不影響總體流程理解。
3.eventListener.callStart(this);可以看到前面構(gòu)建的eventListener起到作用了,這里先回調(diào)callStart方法。
4.client.dispatcher().enqueue(new AsyncCall(responseCallback));這里我們就需要先回到OkHttpClient的源碼中。
public Dispatcher dispatcher() {
return dispatcher;
}
可以看出返回了一個(gè)僅僅是返回了一個(gè)DisPatcher對(duì)象,那么就追到Dispatcher源碼中。
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
這里先對(duì)Dispatcher的成員變量做個(gè)初步的認(rèn)識(shí)。
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private @Nullable Runnable idleCallback;
/** Executes calls. Created lazily. */
private @Nullable 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<>();
...
}
可以看到,這里用三個(gè)隊(duì)列ArrayDeque用于保存Call對(duì)象,分為三種狀態(tài)異步等待,同步running,異步running。
所以這里的邏輯就比較清楚了。
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
當(dāng)正在執(zhí)行的異步隊(duì)列個(gè)數(shù)小于maxRequest(64)并且請(qǐng)求同一個(gè)主機(jī)的個(gè)數(shù)小于maxRequestsPerHost(5)時(shí),則將這個(gè)請(qǐng)求加入異步執(zhí)行隊(duì)列runningAsyncCall,并用線程池執(zhí)行這個(gè)call,否則加入異步等待隊(duì)列。這里可以看一下runningCallsForHost方法。
/** Returns the number of running calls that share a host with {@code call}. */
private int runningCallsForHost(AsyncCall call) {
int result = 0;
for (AsyncCall c : runningAsyncCalls) {
if (c.host().equals(call.host())) result++;
}
return result;
}
其實(shí)也是很好理解的,遍歷了runningAsyncCalls,記錄同一個(gè)Host的個(gè)數(shù)。
現(xiàn)在來看一個(gè)AsyncCall的源碼,這塊基本上是核心執(zhí)行的地方了。
final class AsyncCall extends NamedRunnable {
。。。
}
看一個(gè)類,首先看一下這個(gè)類的結(jié)構(gòu),可以看到AsyncCall繼承了NameRunnable類。
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();
}
可以看到NamedRunnable是一個(gè)抽象類,首先了Runnable接口,這就很好理解了,接著看run方法,可以看到,這里將當(dāng)前執(zhí)行的線程的名字設(shè)為我們?cè)跇?gòu)造方法中傳入的名字,接著執(zhí)行execute方法,finally再設(shè)置回來。所以現(xiàn)在我們理所當(dāng)然的回到AsyCall找execute方法了。
@Override protected void execute() {
boolean signalledCallback = false;
try {
//異步和同步走的是同樣的方式,主不過在子線程中執(zhí)行
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);
}
}
終于,找到了Response的身影,那么就意味著執(zhí)行網(wǎng)絡(luò)請(qǐng)求就在getResponseWithInterceptorChain()方法中,后面的代碼其實(shí)基本上就是一些接口回調(diào),回調(diào)當(dāng)前Call的執(zhí)行狀態(tài),這里就不分析了,這里我們重點(diǎn)看一下getResponseWithInterceptorChain()這個(gè)方法,給我的感覺這個(gè)方法就是okHttp的精髓。
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
//失敗和重定向過濾器
interceptors.add(retryAndFollowUpInterceptor);
//封裝request和response過濾器
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//緩存相關(guān)的過濾器,負(fù)責(zé)讀取緩存直接返回、更新緩存
interceptors.add(new CacheInterceptor(client.internalCache()));
//負(fù)責(zé)和服務(wù)器建立連接
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//配置 OkHttpClient 時(shí)設(shè)置的 networkInterceptors
interceptors.addAll(client.networkInterceptors());
}
//負(fù)責(zé)向服務(wù)器發(fā)送請(qǐng)求數(shù)據(jù)、從服務(wù)器讀取響應(yīng)數(shù)據(jù)(實(shí)際網(wǎng)絡(luò)請(qǐng)求)
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
可以看到,這里首先new了一個(gè)Interceptor的ArrayList,然后分別加入了各種各樣的Interceptor,所以當(dāng)我們默認(rèn)創(chuàng)建okHttpClient時(shí),okHttp默認(rèn)會(huì)給我們實(shí)現(xiàn)這些過濾器,每個(gè)過濾器執(zhí)行不同的任務(wù),這個(gè)思想太屌了有木有,每個(gè)過濾器負(fù)責(zé)自己的任務(wù),各個(gè)過濾器間相互不耦合,高內(nèi)聚,低耦合,對(duì)拓展放開巴拉巴拉等一系列設(shè)計(jì)思想有木有,這里可以對(duì)比一下Volley源碼中的思想,Volley的處理是將緩存,網(wǎng)絡(luò)請(qǐng)求等一系列操作揉在一起寫,導(dǎo)致用戶對(duì)于Volley的修改只能通過修改源碼方式,而修改就必須要充分閱讀理解volley整個(gè)的流程,可能一部分的修改會(huì)影響全局的流程,而這里,將不同的職責(zé)的過濾器分別單獨(dú)出來,用戶只需要對(duì)關(guān)注的某一個(gè)功能項(xiàng)進(jìn)行理解,并可以進(jìn)行擴(kuò)充修改,一對(duì)比,okHttp在這方面的優(yōu)勢(shì)立馬體現(xiàn)出來了。這里大概先描述一下幾個(gè)過濾器的功能:
retryAndFollowUpInterceptor——失敗和重定向過濾器
BridgeInterceptor——封裝request和response過濾器
CacheInterceptor——緩存相關(guān)的過濾器,負(fù)責(zé)讀取緩存直接返回、更新緩存
ConnectInterceptor——負(fù)責(zé)和服務(wù)器建立連接,連接池等
networkInterceptors——配置 OkHttpClient 時(shí)設(shè)置的 networkInterceptors
CallServerInterceptor——負(fù)責(zé)向服務(wù)器發(fā)送請(qǐng)求數(shù)據(jù)、從服務(wù)器讀取響應(yīng)數(shù)據(jù)(實(shí)際網(wǎng)絡(luò)請(qǐng)求)
添加完過濾器后,就是執(zhí)行過濾器了,這里也很重要,一開始看比較難以理解。
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
可以看到這里創(chuàng)建了一個(gè)RealInterceptorChain,并調(diào)用了proceed方法,這里注意一下0這個(gè)參數(shù)。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection 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.httpCodec != null && !this.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.httpCodec != 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, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != 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;
}
第一眼看,腦袋可能會(huì)有點(diǎn)發(fā)麻,稍微處理一下。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
。。。
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
。。。
return response;
}
這樣就很清晰了,這里index就是我們剛才的0,也就是從0開始,如果index超過了過濾器的個(gè)數(shù)拋出異常,后面會(huì)再new一個(gè)RealInterceptorChain,而且會(huì)將參數(shù)傳遞,并且index+1了,接著獲取index的interceptor,并調(diào)用intercept方法,傳入新new的next對(duì)象,這里可能就有點(diǎn)感覺了,這里用了遞歸的思想來完成遍歷,為了驗(yàn)證我們的想法,隨便找一個(gè)interceptor,看一下intercept方法。
public final class ConnectInterceptor implements Interceptor {
public final OkHttpClient client;
public ConnectInterceptor(OkHttpClient client) {
this.client = client;
}
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
。。。暫時(shí)沒必要看。。。
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
}
可以看到這里我們拿了一個(gè)ConnectInterceptor的源碼,這里得到chain后,進(jìn)行相應(yīng)的處理后,繼續(xù)調(diào)用proceed方法,那么接著剛才的邏輯,index+1,獲取下一個(gè)interceptor,重復(fù)操作,所以現(xiàn)在就很清楚了,這里利用遞歸循環(huán),也就是okHttp最經(jīng)典的責(zé)任鏈模式。
4.同步請(qǐng)求
異步看完,同步其實(shí)就很好理解了。
/**
* 同步請(qǐng)求
*/
@Override public Response execute() throws IOException {
//檢查這個(gè)call是否運(yùn)行過
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
//回調(diào)
eventListener.callStart(this);
try {
//將請(qǐng)求加入到同步隊(duì)列中
client.dispatcher().executed(this);
//創(chuàng)建過濾器責(zé)任鏈,得到response
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);
}
}
可以看到基本上流程都一致,除了是同步執(zhí)行,核心方法走的還是getResponseWithInterceptorChain()方法。

到這里okHttp的流程基本上分析完了,接下來就是對(duì)Inteceptor的分析了,這里獻(xiàn)上一張偷來的圖(原圖來源->拆輪子系列:拆 OkHttp)便于理解流程,希望能分析完所有的Inteceptor吧!
OkHttp源碼