okhttp中一開始以為攔截器使用的是動態(tài)代理,類似Spring MVC里面的攔截器,當(dāng)然okhttp僅僅為底層框架是沒必要代理的,不過retrofit 使用的是動態(tài)代理,后來翻看源碼為責(zé)任鏈加遞歸調(diào)用
攔截器調(diào)用順序
RealCall.java
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)); //最底下是CallServerInterceptor 攔截器
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
- 在配置 OkHttpClient 時設(shè)置的 interceptors;
- 負(fù)責(zé)失敗重試以及重定向的 RetryAndFollowUpInterceptor;
- 負(fù)責(zé)把用戶構(gòu)造的請求轉(zhuǎn)換為發(fā)送到服務(wù)器的請求、把服務(wù)器返回的 響應(yīng)轉(zhuǎn)換為用戶友好的響應(yīng)的 BridgeInterceptor;
- 負(fù)責(zé)讀取緩存直接返回、更新緩存的 CacheInterceptor;
- 負(fù)責(zé)和服務(wù)器建立連接的 ConnectInterceptor;
- 配置 OkHttpClient 時設(shè)置的 networkInterceptors;
- 負(fù)責(zé)向服務(wù)器發(fā)送請求數(shù)據(jù)、從服務(wù)器讀取響應(yīng)數(shù)據(jù)的 CallServerInterceptor。
RealInterceptorChain.java
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
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.httpCodec != 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.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);
//索引+1 ,這里是使用了RealInterceptorChain的鏈 進(jìn)行遞歸管理的,而不是我們普通上的那種遞歸,這種使用方式值得考慮,
//這樣可以進(jìn)行一些判斷等處理,遞歸的是類,不是方法,很棒
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");
}
return response;
}
CacheInterceptor.java
// If we don't need the network, we're done.
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
Response networkResponse = null;
try {
networkResponse = chain.proceed(networkRequest); // 此處進(jìn)行了遞歸處理
} finally {
// If we're crashing on I/O or otherwise, don't leak the cache body.
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
CallServerInterceptor.java
在最后一個Intercept 里面是直接返回了response 而不是進(jìn)行繼續(xù)遞歸
httpCodec.finishRequest();
if (responseBuilder == null) {
responseBuilder = httpCodec.readResponseHeaders(false);
}
Response response = responseBuilder // 這里直接進(jìn)行了new操作
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
streamAllocation.noNewStreams();
}
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
總結(jié):
- 首先定義攔截器一層層往下運(yùn)行,直到最底下的攔截器返回response ,一層層往上透傳,直到最上層,然后處理一些信息,這個很像事件傳遞機(jī)制,類比下