前兩天我們介紹了喇聊,基本使用和如何查看源碼牛柒,今天我們正式進(jìn)入源碼分析流程。
流程圖
首先我們先看一看它的請(qǐng)求流程棒旗,在Okhttp3中請(qǐng)求是基于攔截器原理喘批,源代碼如下:
源碼路徑:okhttp3/RealCall.java
// 開始執(zhí)行整個(gè)請(qǐng)求
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
// 攔截器棧
List<Interceptor> interceptors = new ArrayList<>();
// 前文說過的 普通攔截器
interceptors.addAll(client.interceptors());
// 重試攔截器,網(wǎng)絡(luò)錯(cuò)誤铣揉、請(qǐng)求失敗等
interceptors.add(retryAndFollowUpInterceptor);
// 橋接攔截器饶深,主要是重構(gòu)請(qǐng)求頭即header
interceptors.add(new BridgeInterceptor(client.cookieJar()));
// 緩存攔截器
interceptors.add(newCacheInterceptor(client.internalCache()));
// 連接攔截器,連接服務(wù)器逛拱,https包裝
interceptors.add(new ConnectInterceptor(client));
// 網(wǎng)絡(luò)攔截器敌厘,websockt不支持,同樣是自定義
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
// 服務(wù)攔截器朽合,主要是發(fā)送(write俱两、input)、讀炔懿健(read宪彩、output)數(shù)據(jù)
interceptors.add(new CallServerInterceptor(forWebSocket));
// 開啟調(diào)用鏈
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
研究Okhttp3的源碼,從此處開始讲婚,一個(gè)一個(gè)攔截器尿孔,讀懂即可。不得不說這種方式真的很棒筹麸,清晰明了活合。
整體框架圖(圖片來源網(wǎng)絡(luò),感謝作者):
通過上圖物赶,想必對(duì)Okhttp3的實(shí)現(xiàn)方式白指,已經(jīng)有了基本的認(rèn)識(shí)下面我們就一步一具體分析。
構(gòu)造HttpClient
HttpClient采用了建造者設(shè)計(jì)模式來實(shí)例化酵紫。本身有多個(gè)字段用于全局對(duì)象侵续,比去Cache倔丈、Dns等
-
靜態(tài)代碼塊構(gòu)造全局緩存
static { Internal.instance = new Internal() { // 略 @Override public void setCache(OkHttpClient.Builder builder, InternalCache internalCache) { // 寫入緩存,指的是響應(yīng)數(shù)據(jù)緩存 builder.setInternalCache(internalCache); } // 從緩存中獲取有效的連接状蜗,僅支持Http/2需五, 本質(zhì)就是從內(nèi)存的ConnectiongPol中的Deque讀取 @Override public RealConnection get( ConnectionPool pool, Address address, StreamAllocation streamAllocation) { return pool.get(address, streamAllocation); } // 將連接緩存到連接池中 @Override public void put(ConnectionPool pool, RealConnection connection) { pool.put(connection); } // 線路的緩存,多host多ip的青款 @Override public RouteDatabase routeDatabase(ConnectionPool connectionPool) { return connectionPool.routeDatabase; } // 略 } // 此處有很多種數(shù)據(jù)緩存處理轧坎,不了解并不影響代碼分析宏邮,如有興趣可自行研究
Dispatcher, 分發(fā)請(qǐng)求缸血,內(nèi)部是有一個(gè)ThreadPoolExecutor
Proxy蜜氨, 代理連接,分三種類型直接(DIRECT)捎泻、Http(http)飒炎、SOCKS。
ProxySelector笆豁,線路選擇器郎汪,對(duì)應(yīng)Okhttp的一大特點(diǎn),自行線路選擇闯狱,找到合適的連接
Cache煞赢, 真正的緩存實(shí)現(xiàn)
SSLSocketFactory, Https的支持
ConnectionPool哄孤, 連接池
Dns照筑,dns解析(Java實(shí)現(xiàn))
其他,如超時(shí)時(shí)間等
發(fā)起請(qǐng)求
我們都知道一個(gè)請(qǐng)求有多部分組成瘦陈,同樣Okhttp3創(chuàng)建一個(gè)請(qǐng)求也要多部分凝危。
- 構(gòu)造請(qǐng)求頭
- 構(gòu)造請(qǐng)求體
- 發(fā)送一個(gè)請(qǐng)求
通過以上三步我們就可以完成一次請(qǐng)求。
請(qǐng)求頭
header并非每個(gè)請(qǐng)求都需要晨逝,要看與服務(wù)端是如何定義的媒抠,通常一個(gè)請(qǐng)求會(huì)默認(rèn)一些頭,比如Content-Type咏花,Accept-Encoding,Connection等對(duì)應(yīng)http協(xié)議
Header本質(zhì)上就是一個(gè)Map阀趴,只是在封裝了一層而已昏翰,但是Okhttp3的實(shí)現(xiàn)不是這樣,而是一個(gè)String數(shù)據(jù)刘急,key + value的形式棚菊,即一個(gè)頭占用數(shù)組的兩位:
每一個(gè)色塊對(duì)應(yīng)一個(gè)header,代碼如下:
// 源碼路徑 okhttp3/Headers.java
public final class Headers {
private final String[] namesAndValues;
// 略
Builder addLenient(String name, String value) {
namesAndValues.add(name);
namesAndValues.add(value.trim());
return this;
}
// 略
}
請(qǐng)求體
請(qǐng)求體有多種形式叔汁,對(duì)應(yīng)的父類是RequestBody统求,有文件形式检碗、Json等,MediaType決定了是何種形式码邻,通常我們用的是FromBody和MultipartBody
-
FromBody
public final class FormBody extends RequestBody { private static final MediaType CONTENT_TYPE = MediaType.parse("application/x-www-form-urlencoded"); private final List<String> encodedNames; // 參數(shù)名稱 private final List<String> encodedValues; // 參數(shù)值 // 構(gòu)造者 public static final class Builder { private final List<String> names = new ArrayList<>(); private final List<String> values = new ArrayList<>(); public Builder add(String name, String value) { names.add(HttpUrl.canonicalize(name, FORM_ENCODE_SET, false, false, true, true)); values.add(HttpUrl.canonicalize(value, FORM_ENCODE_SET, false, false, true, true)); return this; } //構(gòu)造一個(gè)實(shí)例 public FormBody build() { return new FormBody(names, values); } } }
-
MultipartBody
MultipartBody原理基本一致折剃,區(qū)別在于他可以發(fā)送表單的同時(shí)也可以發(fā)送文件數(shù)據(jù),再次不在贅述像屋。
構(gòu)造一個(gè)Request
有了上面兩個(gè)步驟怕犁,接下了就自然而讓產(chǎn)生一個(gè)Request,顧名思義它就是對(duì)請(qǐng)求的封裝己莺,包括請(qǐng)求方式奏甫,請(qǐng)求頭,請(qǐng)求體凌受,請(qǐng)求路徑等,源代碼碼也是比較簡(jiǎn)單阵子,一看即明白。
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final RequestBody body;
final Object tag;
}
Call
有了準(zhǔn)備工作胜蛉,現(xiàn)在我們就要發(fā)射了挠进,Call是一個(gè)概念的封裝,就像一列火車腾么,蓄勢(shì)待發(fā)奈梳,在鐵軌停靠準(zhǔn)備出發(fā)一樣
Call是一個(gè)接口解虱,實(shí)現(xiàn)類只有一個(gè)RealCall攘须,上面我們提到的流程就是在RealCall中。
public interface Call extends Cloneable {
Request request(); // 獲取請(qǐng)求封裝的數(shù)據(jù)
Response execute() throws IOException; // 同步執(zhí)行
void enqueue(Callback responseCallback); // 異步執(zhí)行
void cancel(); // 取消請(qǐng)求
boolean isExecuted();
boolean isCanceled();
Call clone();
interface Factory {
Call newCall(Request request);
}
}
// 重點(diǎn)看看中文注釋處即可
final class RealCall implements Call {
final OkHttpClient client;
// 重試攔截器
final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
/** The application's original request unadulterated by redirects or auth headers. */
final Request originalRequest;
final boolean forWebSocket;
// Guarded by this.
private boolean executed;
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
@Override public Request request() {
return originalRequest;
}
// 同步執(zhí)行的實(shí)現(xiàn)
@Override public Response execute() throws IOException {
// 一個(gè)call只能執(zhí)行一次
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
// 將請(qǐng)求放在殴泰,請(qǐng)求池中執(zhí)行于宙,此處會(huì)立即執(zhí)行
client.dispatcher().executed(this);
// 獲取結(jié)果,即執(zhí)行多個(gè)鏈接器的調(diào)用鏈
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
private void captureCallStackTrace() {
Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
}
// 異步執(zhí)行悍汛,不管行返回結(jié)果
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
// AsyncCall是一個(gè)Runnable的實(shí)現(xiàn)類捞魁,同時(shí)一個(gè)是RealCall的內(nèi)部類
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
@Override public void cancel() {
retryAndFollowUpInterceptor.cancel();
}
@Override public synchronized boolean isExecuted() {
return executed;
}
@Override public boolean isCanceled() {
return retryAndFollowUpInterceptor.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
@Override public RealCall clone() {
return new RealCall(client, originalRequest, forWebSocket);
}
StreamAllocation streamAllocation() {
return retryAndFollowUpInterceptor.streamAllocation();
}
// 異步執(zhí)行的線程封裝,Android基本就是這里了
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 {
// 執(zhí)行調(diào)用鏈离咐,是不是很重要谱俭,哈哈
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);
}
}
}
/**
* Returns a string that describes this call. Doesn't include a full URL as that might contain
* sensitive information.
*/
String toLoggableString() {
return (isCanceled() ? "canceled " : "")
+ (forWebSocket ? "web socket" : "call")
+ " to " + redactedUrl();
}
String redactedUrl() {
return originalRequest.url().redact();
}
// 最重要的入口了
// 最重要的入口了
// 最重要的入口了
// 重要事情說三遍
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 (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
// 脊髓代碼開始處
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
}
看來上面的代碼,是不是被人家的想法折服宵蛀。更精妙的還在后面呢昆著,不要急。到此术陶,一個(gè)請(qǐng)求已經(jīng)完成凑懂,發(fā)送和接收,(不關(guān)心內(nèi)部實(shí)現(xiàn)的話)梧宫。接下來我們?cè)賮砜纯唇咏鳎B接器是如何工作的摆碉。
攔截器工作原理
Interceptor是一個(gè)接口,主要是對(duì)請(qǐng)求和響應(yīng)的處理脓豪,而實(shí)現(xiàn)攔截器調(diào)用鏈的是其內(nèi)部接口Chain
public interface Interceptor {
// 管攔截
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
// 管分發(fā),前行
Response proceed(Request request) throws IOException;
Connection connection();
}
}
Interceptor.Chain的實(shí)現(xiàn)類只有一個(gè)RealInterceptorChain巷帝,也是處理調(diào)用過程的實(shí)現(xiàn),其內(nèi)部有個(gè)List裝載了所有攔截器跑揉,大家想必也猜到了锅睛,對(duì),就是迭代历谍,當(dāng)然也不是簡(jiǎn)簡(jiǎn)單單的接待了事现拒。讓我們看看源碼實(shí)現(xiàn)。
// RealCall.getResponseWithInterceptorChain()中創(chuàng)建了一個(gè)實(shí)例
public final class RealInterceptorChain implements Interceptor.Chain {
// RealCall.getResponseWithInterceptorChain()中已經(jīng)賦值
private final Request request;
private final List<Interceptor> interceptors;
// 下面屬性會(huì)在執(zhí)行攔截器的過程中一步一步賦值
private final StreamAllocation streamAllocation;
private final HttpCodec httpCodec;
private final Connection connection;
private final int index;
private int calls;
public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
HttpCodec httpCodec, Connection connection, int index, Request request) {
this.interceptors = interceptors;
this.connection = connection;
this.streamAllocation = streamAllocation;
this.httpCodec = httpCodec;
this.index = index;
this.request = request;
}
// 實(shí)現(xiàn)了父類proceed方法
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
// 處理調(diào)用
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
Connection connection) throws IOException {
// 1望侈、迭代攔截器集合
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// 略印蔬。。脱衙。
// 2侥猬、創(chuàng)建行的實(shí)例, 并將計(jì)數(shù)器+1
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
// 3捐韩、 取出下一個(gè)攔截器
Interceptor interceptor = interceptors.get(index);
// 4退唠、執(zhí)行攔截器方法,攔截器中又會(huì)調(diào)用proceed()方法
Response response = interceptor.intercept(next);
// 略荤胁。瞧预。。
return response;
}
}
看了上面的代碼是不是還不明白仅政,到底怎么實(shí)現(xiàn)的垢油,實(shí)際上就是迭代+遞歸。
每一個(gè)RealInterceptorChain會(huì)對(duì)應(yīng)一個(gè)Interceptor圆丹,然后Interceptor在產(chǎn)生下一個(gè)RealInterceptorChain滩愁,知道List迭代完成。
總結(jié)
Okhttp3的調(diào)用流程基本原理就是這樣辫封,重要的是思想硝枉,整個(gè)流程一氣呵成,完全解耦倦微。