寫在開頭
文章地址:https://juejin.im/post/5e1be39b6fb9a02fcd130d1f
本文是對該文章的個(gè)人理解總結(jié),僅用于個(gè)人復(fù)習(xí),有需要看此文章即可。
大綱
- 使用
- 解析
- 責(zé)任鏈模式
- 總結(jié)
使用
最簡單的“Get”請求
// 實(shí)例客戶端
val okHttpClient = OkHttpClient()
// 構(gòu)建 request 請求參數(shù)
val request = Request.Builder().url("http://www.baidu.com").build()
//執(zhí)行同步請求并返回
val response = okHttpClient.newCall(request).execute()
解析
解析上述三步
1. OkHttpClient()
1.第一步
public OkHttpClient() {
//實(shí)例 Builder,構(gòu)建者模式
this(new Builder());
}
2.第二步
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
//...其他配置
}
public static final class Builder {
Dispatcher dispatcher;
//...其他配置
3.第三步
//new Builder() 會創(chuàng)建一系列默認(rèn)配置
public Builder() {
dispatcher = new Dispatcher();
//...其他配置
}
}
總結(jié)來說:實(shí)例 OkHttp(),就會實(shí)例一個(gè) Builder(),它里面會初始化一系列配置。(攔截器,請求超時(shí)等)
2. Request.Builder().url("地址").build()
顯然也是使用了“Builder”模式
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
默認(rèn)“GET”方法,這里我們再加了請求的“url”
3. okHttpClient.newCall(request)
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
//初始化一些配置
...
}
可以看出“okHttpClient”的“newCall”實(shí)際是使用了“RealCall”類
4. execute()
最后調(diào)用“RealCall”的“execute”請求
@Override public Response execute() throws IOException {
//同步檢查有沒有多次執(zhí)行過
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//捕獲棧堆跟蹤,不需要理會
captureCallStackTrace();
try {
//1. 添加請求到隊(duì)列
client.dispatcher().executed(this);
//2. 重點(diǎn),可先看最后的責(zé)任鏈的個(gè)人理解
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
//3. 從隊(duì)列移除請求
client.dispatcher().finished(this);
}
}
//1. 添加請求到隊(duì)列,從 okHttpClient 拿到 dispatcher( Dispatcher 類)
// dispatcher 在實(shí)例 Buidler 時(shí)初始化了
// runningSyncCall 是 一個(gè)雙端隊(duì)列 Deque
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
//3. 從隊(duì)列移除請求,沒有這個(gè) call 就報(bào)錯(cuò)
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!");
...
}
...
}
//2. 重點(diǎn),使用“責(zé)任鏈模式”獲取請求結(jié)果
Response getResponseWithInterceptorChain() throws IOException {
//實(shí)例 list 存放一些列攔截器
List<Interceptor> interceptors = new ArrayList<>();
//將自己在 OkHttpClient 添加的攔截器放入,這里是我沒有添加
interceptors.addAll(client.interceptors());
//重試并跟蹤攔截器,負(fù)責(zé)失敗的重試及重定向
interceptors.add(retryAndFollowUpInterceptor);
//負(fù)責(zé)添加必要的“Header”,接收響應(yīng)式,移除必要的“Header”
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//負(fù)責(zé)緩存的讀取,更新
interceptors.add(new CacheInterceptor(client.internalCache()));
//負(fù)責(zé)和服務(wù)器的連接
interceptors.add(new ConnectInterceptor(client));
//若不是 webSocket 請求,默認(rèn)是false
if (!forWebSocket) {
// okHttpClient 設(shè)置的網(wǎng)絡(luò)攔截器 ,這里也沒有設(shè)置
interceptors.addAll(client.networkInterceptors());
}
//負(fù)責(zé)向服務(wù)器發(fā)送請求數(shù)據(jù),從服務(wù)器相應(yīng)數(shù)據(jù)
interceptors.add(new CallServerInterceptor(forWebSocket));
//責(zé)任鏈實(shí)例,RealInterceptorChain 實(shí)例
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
//開始責(zé)任鏈模式調(diào)用
return chain.proceed(originalRequest);
}
5. chain.proceed(originalRequest)
// RealInterceptorChain 的 proceed 方法
@Override public Response proceed(Request request) throws IOException {
//這里的 streamAllocation, httpCodec, connection 開始是空的
//但經(jīng)過責(zé)任鏈的調(diào)用,將攔截器的結(jié)果返回來后就不為空
return proceed(request, streamAllocation, httpCodec, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//若 index 大于等于攔截器集合 就報(bào)錯(cuò)
//開始為零,其余的都是其他攔截器責(zé)任鏈模式傳來的索引
//看下面的 RealInterceptorChain next = new RealInterceptorChain
if (index >= interceptors.size()) throw new AssertionError();
//標(biāo)記,一般都是 ++ 后為1, 除非同一個(gè)Chain實(shí)例被調(diào)用了多次 proceed
calls++;
//一開始 httpCode,connection為 null
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");
}
// httpCodec同上,calls:大于 1 表示自己多次調(diào)用了 proceed
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// 實(shí)例下一個(gè)攔截器 (參數(shù):index + 1)
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
//調(diào)用當(dāng)前攔截器的 interceptor方法,傳入下一個(gè)攔截器責(zé)任鏈實(shí)例
//該攔截器處理到處理不了的時(shí)候,就通過這個(gè)責(zé)任鏈的next.processd 回到該方法
//簡單來說:有必要就通過這個(gè)實(shí)例叫下一個(gè)攔截器做事
Response response = interceptor.intercept(next);
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
return response;
}
每一個(gè)攔截器的 intercept 方法里都有一個(gè) chain.proceed,除了集合添加的最后一個(gè) CallServerInterceptor,因?yàn)樗鬀]有攔截器了。
在 CallServerInterceptor 返回 response 后,其他攔截器再處理完 自己chain.proceed后的方法,最終會返回一個(gè)完整的 response
舉例看第一個(gè)攔截器 “RetryAndFollowUpInterceptor”,這個(gè)攔截器就組裝了 StreamAllocation streamAllocation參數(shù)
//Chain:這里是下一個(gè)攔截器的責(zé)任鏈
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//實(shí)例 StreamAllocation
streamAllocation = new StreamAllocation(
client.connectionPool(), createAddress(request.url()), callStackTrace);
...
Response response = null;
boolean releaseConnection = true;
try {
//將 streamAllocation 也返回給下一個(gè)攔截器處理
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
...
}
...
}
責(zé)任鏈模式
我能做的我做,不能的交給下一個(gè)人做
比如(這例子是模仿其他作者的舉例寫的,但實(shí)在忘記在哪看的 - -):
主題:公司活動(dòng),需要申請 500元 經(jīng)費(fèi)。
公司審批經(jīng)費(fèi)的額度根據(jù)職位不同而不同,部門經(jīng)理只能批200元,總經(jīng)理能批1000元。這時(shí)我交給了部門經(jīng)理審批,部門經(jīng)理看數(shù)目后提交給總經(jīng)理,總經(jīng)理確定簽字。
這就是責(zé)任鏈,能做的就做,不行的就給下一個(gè)人處理,自己不再負(fù)責(zé),當(dāng)事人不清楚是誰最終完成了簽字。
交給別人后自己不再負(fù)責(zé),這也是純種的責(zé)任鏈模式,但純種的責(zé)任鏈模式在實(shí)際需求中比較少。
實(shí)際需求中的責(zé)任鏈,一般都是:我先處理一些東西,發(fā)現(xiàn)有些東西處理不了,然后交給其他人繼續(xù)處理,最后將某些結(jié)果返回來再接著處理,OkHttp的責(zé)任鏈模式就是如此。
總結(jié)
上面講了同步請求,異步請求最終也會調(diào)用 getResponseWithInterceptorChain() 組裝數(shù)據(jù),總體流程圖如下,

注:原文里面還有一些攔截器的詳解