介紹
攔截器鏈贸典,采用責(zé)任鏈模式拓劝,將一次事物的耦合度降低雏逾。
源碼分析
RealInterceptorChain
RealInterceptorChain就是個(gè)List<Interceptor>,源碼比較簡(jiǎn)單,主要功能proceed
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
...
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec, connection, index + 1,request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
...
return response;
}
RetryAndFollowUpInterceptor
RetryAndFollowUpInterceptor的責(zé)任是失敗重試和重定向郑临,主要功能在于
intercept
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//創(chuàng)建一個(gè)新的流
streamAllocation = new StreamAllocation(
client.connectionPool(), createAddress(request.url()), callStackTrace);
int followUpCount = 0;
//重定向可能產(chǎn)生多個(gè)Response
Response priorResponse = null;
//循環(huán)直到取消或者拋出exception
while (true) {
...
//輔助判斷是否要釋放連接
boolean releaseConnection = true;
try {
//取得下級(jí)返回的response
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (){
//各種異常捕捉處理
...
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
...
//重定向栖博,根據(jù)返回response生成新的request
Request followUp = followUpRequest(response);
...
//判斷是否是sameConnection(host==host&&port==port&&scheme==scheme)可復(fù)用鏈路
if (!sameConnection(response, followUp.url())) {
streamAllocation.release();
streamAllocation = new StreamAllocation(
client.connectionPool(), createAddress(followUp.url()), callStackTrace);
} else if (streamAllocation.codec() != null) {
throw new IllegalStateException("Closing the body of " + response
+ " didn't close its backing stream. Bad interceptor?");
}
request = followUp;
priorResponse = response;
}
}
BridgeInterceptor
BridgeInterceptor可以理解成轉(zhuǎn)換器
Bridges from application code to network code. First it builds a network request from a user request. Then it proceeds to call the network. Finally it builds a user response from the network response.
源碼非常簡(jiǎn)單,主要內(nèi)容在于intercept
@Override public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
//組織Request Header包括這是keep-alive, Cookie添加厢洞,gzip等
....
//傳遞
Response networkResponse = chain.proceed(requestBuilder.build());
//組織Response Header 包括cookie保存更新仇让,Gzip解壓等
....
return responseBuilder.build();
}
CacheInterceptor
緩存攔截器更具客戶(hù)端是否支持緩存和相關(guān)的緩存策略決定從網(wǎng)絡(luò)獲取或者從緩存獲取Response,主要內(nèi)容在于intercept
public Response intercept(Chain chain) throws IOException {
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
long now = System.currentTimeMillis();
//根據(jù)緩存策略獲取緩存Request和Response
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
...
//緩存不可用或者緩存過(guò)期躺翻,網(wǎng)絡(luò)獲取
Response networkResponse = null;
try {
networkResponse = chain.proceed(networkRequest);
} finally {
// If we're crashing on I/O or otherwise, don't leak the cache body.
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
...
//更新緩存
return response;
}
ConnectInterceptor
ConnectInterceptor建立與服務(wù)器的連接
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
//獲取可復(fù)用流
StreamAllocation streamAllocation = realChain.streamAllocation();
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET");
HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);
//根據(jù)HTTP/1.x(keep-alive)和HTTP/2(流復(fù)用)的復(fù)用機(jī)制丧叽,發(fā)起連接
RealConnection connection = streamAllocation.connection();
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
CallServerInterceptor
CallServerInterceptor和服務(wù)器交互數(shù)據(jù)
@Override public Response intercept(Chain chain) throws IOException {
...
long sentRequestMillis = System.currentTimeMillis();
//發(fā)送header數(shù)據(jù)
httpCodec.writeRequestHeaders(request);
Response.Builder responseBuilder = null;
//根據(jù)是否支持100-continue,發(fā)送body數(shù)據(jù)
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
...
}
httpCodec.finishRequest();
if (responseBuilder == null) {
responseBuilder = httpCodec.readResponseHeaders(false);
}
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
//response處理
...
return response;
}
擴(kuò)展
責(zé)任鏈中大體流程分析完公你,其中有很多可以深究的地方踊淳,包括緩存和多路復(fù)用的實(shí)現(xiàn)
緩存
Okhttp緩存涉及到internal cache(接口設(shè)計(jì)),cache(實(shí)現(xiàn)類(lèi))陕靠,CacheStrategy(緩存策略)迂尝,DiskLruCache(lru cache實(shí)現(xiàn)),具體可以參考BlackSwift寫(xiě)的
OkHttp3源碼分析[緩存策略] ,OkHttp3源碼分析[DiskLruCache]
多路復(fù)用
多路復(fù)用設(shè)計(jì)到包括StreamAllocation(上層流)剪芥,ConnectionPool(連接池)垄开, http1Codec,http2Codec税肪。
首先要了解HTTP/1(keep-alive)和HTTP/2(二進(jìn)制流)的相關(guān)知識(shí)溉躲,才能更好的理解OKhttp多路復(fù)用的實(shí)現(xiàn),具體可以參考
OkHttp 3.7源碼分析(五)——連接池和
OkHttp3源碼分析[復(fù)用連接池]