OkHttp3是目前Android熱門(mén)的網(wǎng)絡(luò)請(qǐng)求框架之一轰绵,本篇來(lái)分析一下OkHttp3最主要的幾部分:
- 同步扼菠、異步請(qǐng)求流程
- 攔截器對(duì)請(qǐng)求的補(bǔ)充和攔截
連接池的復(fù)用連接和緩存連接也是一大亮點(diǎn)化焕,不過(guò)水平有限萄窜,暫時(shí)先不分析
OkHttpClient構(gòu)建
OkHttp3請(qǐng)求前需要?jiǎng)?chuàng)建一個(gè)OkHttpClient,所有的配置都在OkHttpClient的構(gòu)建時(shí)配置撒桨,它使用了構(gòu)建者模式(Builder模式)來(lái)具體化每個(gè)配置查刻,并且提供默認(rèn)配置。
- 如果想使用默認(rèn)配置凤类,可直接使用new關(guān)鍵字創(chuàng)建(也是使用默認(rèn)配置的Builder來(lái)創(chuàng)建)穗泵,需要自定義配置則創(chuàng)建OkHttpClient.Builder配置類(lèi)傳入client進(jìn)行構(gòu)造。
OkHttpClient client = new OkHttpClient();
//使用默認(rèn)Builder配置來(lái)構(gòu)造client對(duì)象
public OkHttpClient() {
this(new Builder());
}
//自定義Builder配置對(duì)象傳入構(gòu)造client
OkHttpClient(Builder builder) {
//...
}
public static final class Builder {
/**
* 請(qǐng)求分發(fā)器
*/
Dispatcher dispatcher;
@Nullable
Proxy proxy;
List<Protocol> protocols;
List<ConnectionSpec> connectionSpecs;
/**
* 全局請(qǐng)求攔截器列表
*/
final List<Interceptor> interceptors = new ArrayList<>();
/**
* 非WebSocket時(shí)會(huì)添加的請(qǐng)求攔截器
*/
final List<Interceptor> networkInterceptors = new ArrayList<>();
EventListener.Factory eventListenerFactory;
ProxySelector proxySelector;
CookieJar cookieJar;
@Nullable
Cache cache;
/**
* 內(nèi)部緩存谜疤,實(shí)際是緩存的Api接口佃延,內(nèi)部還是調(diào)用Cache對(duì)象中的方法來(lái)實(shí)現(xiàn)緩存
*/
@Nullable
InternalCache internalCache;
SocketFactory socketFactory;
/**
* HTTPS使用的安全套接字Socket工廠
*/
@Nullable
SSLSocketFactory sslSocketFactory;
@Nullable
CertificateChainCleaner certificateChainCleaner;
HostnameVerifier hostnameVerifier;
CertificatePinner certificatePinner;
Authenticator proxyAuthenticator;
Authenticator authenticator;
/**
* 連接池
*/
ConnectionPool connectionPool;
Dns dns;
/**
* 安全套接字層重定向
*/
boolean followSslRedirects;
/**
* 本地重定向
*/
boolean followRedirects;
/**
* 重試連接失敗
*/
boolean retryOnConnectionFailure;
int connectTimeout;
int readTimeout;
int writeTimeout;
int pingInterval;
/**
* 默認(rèn)的配置
*/
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
//...
}
同步請(qǐng)求流程分析
同步請(qǐng)求就是直接在當(dāng)前線程請(qǐng)求,會(huì)阻塞線程夷磕,所以如果在主線程請(qǐng)求履肃,必須開(kāi)啟一個(gè)子線程進(jìn)行請(qǐng)求。
OkHttpClient client = new OkHttpClient();
//創(chuàng)建請(qǐng)求配置類(lèi)Request
Request request =
new Request.Builder()
.url(url)
.build();
//newCall創(chuàng)建請(qǐng)求對(duì)象Call坐桩,再通過(guò)execute()開(kāi)始執(zhí)行尺棋,獲取請(qǐng)求結(jié)果Response對(duì)象
Response response = client.newCall(request).execute();
- 先來(lái)看下client.newCall(request)方法,調(diào)用RealCall.newRealCall()靜態(tài)方法绵跷,創(chuàng)建一個(gè)RealCall對(duì)象膘螟,傳入request請(qǐng)求配置類(lèi)對(duì)象,并指定請(qǐng)求不是WebSocket請(qǐng)求碾局。
/**
* 發(fā)起一個(gè)請(qǐng)求荆残,指定不是WebSocket請(qǐng)求
*
* @param request 請(qǐng)求的配置
*/
@Override
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
- RealCall.newRealCall()靜態(tài)方法,實(shí)際就是創(chuàng)建了RealCall對(duì)象净当,并配置了一個(gè)事件回調(diào)内斯。
/**
* 靜態(tài)方法配置一個(gè)RealCall,RealCall實(shí)現(xiàn)了Call接口蚯瞧,暫時(shí)是唯一實(shí)現(xiàn)嘿期,這么設(shè)計(jì)是為了后續(xù)拓展不同的Call
*
* @param client 請(qǐng)求客戶(hù)端
* @param originalRequest 請(qǐng)求配置類(lèi)
* @param forWebSocket 是否是WebSocket請(qǐng)求
* @return 返回RealCall實(shí)例
*/
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
//為每個(gè)請(qǐng)求配置上外部設(shè)置的事件監(jiān)聽(tīng)回調(diào)
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
- RealCall類(lèi),實(shí)現(xiàn)了Call接口埋合,Call接口規(guī)定了請(qǐng)求可用的Api备徐,內(nèi)部還有一個(gè)Factory接口,newCall()創(chuàng)建Call對(duì)象的方法甚颂∶刍看到newCall()方法秀菱,那么OkHttpClient也肯定實(shí)現(xiàn)了這個(gè)接口(果然沒(méi)猜錯(cuò))
public interface Call extends Cloneable {
//獲取配置的Request對(duì)象
Request request();
//異步請(qǐng)求Api
void enqueue(Callback responseCallback);
//取消任務(wù)
void cancel();
//任務(wù)是否執(zhí)行過(guò)了
boolean isExecuted();
//是否取消了
boolean isCanceled();
//克隆自己
Call clone();
//Call對(duì)象生成工廠
interface Factory {
Call newCall(Request request);
}
}
//OkHttpClient實(shí)現(xiàn)了Call.Factory,所以它充當(dāng)了請(qǐng)求工廠的角色
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
//...
}
//Call接口的實(shí)現(xiàn)
final class RealCall implements Call {
//構(gòu)造方法就是保存了構(gòu)造參數(shù)蹭睡,創(chuàng)建了一個(gè)攔截器衍菱,后面講
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
}
- execute執(zhí)行方法,注意一個(gè)RealCall對(duì)象只能執(zhí)行一次肩豁,重點(diǎn)在getResponseWithInterceptorChain()方法脊串,調(diào)用它后就獲得了一個(gè)Response對(duì)象,那么請(qǐng)求肯定是在這個(gè)方法做的清钥。try-catch異常處理琼锋,finally塊調(diào)用分發(fā)器dispatcher的finished()方法通知分發(fā)器。
/**
* 馬上執(zhí)行祟昭,為同步調(diào)用(非線程池)
*
* @return 請(qǐng)求結(jié)果類(lèi)
*/
@Override
public Response execute() throws IOException {
synchronized (this) {
//執(zhí)行過(guò)一次就不可以再執(zhí)行了缕坎,否則拋出異常
if (executed) {
throw new IllegalStateException("Already Executed");
}
//請(qǐng)求開(kāi)始,將標(biāo)志位設(shè)置為true
executed = true;
}
captureCallStackTrace();
//回調(diào)外部的事件監(jiān)聽(tīng)
eventListener.callStart(this);
try {
//通知分發(fā)器篡悟,開(kāi)始執(zhí)行
client.dispatcher().executed(this);
//重點(diǎn):開(kāi)始責(zé)任鏈調(diào)用谜叹,讓每個(gè)攔截器處理請(qǐng)求request,得出請(qǐng)求結(jié)果Response
Response result = getResponseWithInterceptorChain();
if (result == null) {
throw new IOException("Canceled");
}
return result;
} catch (IOException e) {
//異常搬葬,回調(diào)事件監(jiān)聽(tīng)對(duì)象
eventListener.callFailed(this, e);
throw e;
} finally {
//結(jié)束請(qǐng)求荷腊,調(diào)用分發(fā)器,讓分發(fā)器繼續(xù)執(zhí)行下一個(gè)任務(wù)
client.dispatcher().finished(this);
}
}
- 責(zé)任鏈模式的攔截器踩萎,具體就是創(chuàng)建攔截器到集合列表停局,再創(chuàng)建了一個(gè)RealInterceptorChain攔截器鏈,通過(guò)proceed()方法處理Request對(duì)象香府,最后得出一個(gè)Response請(qǐng)求結(jié)果對(duì)象董栽,整體很干凈,具體工作都交給了攔截器企孩。
- 創(chuàng)建了一個(gè)攔截器列表锭碳,List<Interceptor>。
- 首先勿璃,先添加我們?cè)贑lient中配置的攔截器(全局的)
- 添加失敗和重定向處理的攔截器RetryAndFollowUpInterceptor
- 添加請(qǐng)求Header配置和Cookie的攔截器BridgeInterceptor
- 添加本地緩存和請(qǐng)求攔截的攔截器CacheInterceptor
- 添加服務(wù)請(qǐng)求連接的攔截器ConnectInterceptor
- 如果不是WebSocket請(qǐng)求擒抛,添加我們?cè)贑lient配置的networkInterceptors()攔截器(局部攔截器,在WebSocket中不會(huì)添加的攔截器)
- 添加真正請(qǐng)求服務(wù)器的攔截器CallServerInterceptor
- 創(chuàng)建攔截器鏈RealInterceptorChain补疑,它實(shí)現(xiàn)了Interceptor.Chain接口
- 調(diào)用proceed()方法開(kāi)始遍歷攔截器處理請(qǐng)求配置類(lèi)Request
/**
* 開(kāi)始責(zé)任鏈處理Request請(qǐng)求
*
* @return 請(qǐng)求結(jié)果
*/
Response getResponseWithInterceptorChain() throws IOException {
//攔截器列表
List<Interceptor> interceptors = new ArrayList<>();
//1歧沪、先添加我們?cè)贑lient中配置的全局?jǐn)r截器
interceptors.addAll(client.interceptors());
//2.添加失敗和重定向處理的攔截器
interceptors.add(retryAndFollowUpInterceptor);
//3.對(duì)請(qǐng)求添加一些必要的Header,接受響應(yīng)時(shí)移除掉一些Header
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//4.緩存攔截器莲组,對(duì)請(qǐng)求前本地緩存查詢(xún)和攔截诊胞,對(duì)請(qǐng)求結(jié)果進(jìn)行本地緩存
interceptors.add(new CacheInterceptor(client.internalCache()));
//5.連接攔截器,負(fù)責(zé)請(qǐng)求和服務(wù)器建立連接
interceptors.add(new ConnectInterceptor(client));
//不是WebSocket請(qǐng)求锹杈,添加Client中我們添加的攔截器撵孤,不是全局的迈着,對(duì)WebSocket無(wú)效的攔截器
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
//真正請(qǐng)求服務(wù)器,獲取響應(yīng)的攔截器
interceptors.add(new CallServerInterceptor(forWebSocket));
//創(chuàng)建攔截器鏈
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//開(kāi)始責(zé)任鏈遍歷
return chain.proceed(originalRequest);
}
- Interceptor攔截器接口邪码,主要是intercept()方法裕菠,每種攔截器處理請(qǐng)求Request對(duì)象都在這個(gè)intercept()方法中處理。
/**
* 攔截器接口
*/
public interface Interceptor {
/**
* 攔截回調(diào)方法
*
* @param chain 攔截器鏈
*/
Response intercept(Chain chain) throws IOException;
/**
* 攔截器鏈接口
*/
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
/**
* Returns the connection the request will be executed on. This is only available in the chains
* of network interceptors; for application interceptors this is always null.
*/
@Nullable
Connection connection();
Call call();
int connectTimeoutMillis();
Chain withConnectTimeout(int timeout, TimeUnit unit);
int readTimeoutMillis();
Chain withReadTimeout(int timeout, TimeUnit unit);
int writeTimeoutMillis();
Chain withWriteTimeout(int timeout, TimeUnit unit);
}
}
-
RealInterceptorChain闭专,實(shí)現(xiàn)了Interceptor.Chain接口奴潘,接下來(lái)看proceed()方法
- calls變量自增計(jì)數(shù),記錄這個(gè)攔截器被調(diào)用proceed()方法的次數(shù)喻圃。
- index變量代表自身攔截器在攔截器列表集合中的角標(biāo)位置萤彩,通過(guò)index + 1獲取下一個(gè)攔截器粪滤,調(diào)用它的proceed()方法斧拍,對(duì)Request對(duì)象進(jìn)行處理。
- 重新創(chuàng)建一個(gè)RealInterceptorChain杖小,將攔截器列表肆汹、下一個(gè)攔截器角標(biāo)位置等其他配置傳入,繼續(xù)調(diào)用interceptor攔截器的next()方法繼續(xù)分發(fā)Request對(duì)象予权,并返回一個(gè)Response請(qǐng)求結(jié)果對(duì)象昂勉,并返回出去。
/**
* 攔截器鏈扫腺,管理所有攔截器
*/
public final class RealInterceptorChain implements Interceptor.Chain {
/**
* 攔截器列表
*/
private final List<Interceptor> interceptors;
private final StreamAllocation streamAllocation;
/**
* Http版本處理岗照,Http1和Http2
*/
private final HttpCodec httpCodec;
private final RealConnection connection;
/**
* 當(dāng)前遍歷到的攔截器角標(biāo),每次自增獲取下一個(gè)攔截器
*/
private final int index;
/**
* 請(qǐng)求配置對(duì)象笆环,給每個(gè)攔截器處理
*/
private final Request request;
/**
* 請(qǐng)求對(duì)象
*/
private final Call call;
/**
* 事件回調(diào)對(duì)象
*/
private final EventListener eventListener;
/**
* 連接超時(shí)事件
*/
private final int connectTimeout;
/**
* 讀超時(shí)事件
*/
private final int readTimeout;
/**
* 寫(xiě)超時(shí)事件
*/
private final int writeTimeout;
/**
* 已調(diào)用的攔截器數(shù)量
*/
private int calls;
public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
this.interceptors = interceptors;
this.connection = connection;
this.streamAllocation = streamAllocation;
this.httpCodec = httpCodec;
this.index = index;
this.request = request;
this.call = call;
this.eventListener = eventListener;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
}
//...省略其他方法
/**
* 請(qǐng)求處理
*
* @param request 請(qǐng)求對(duì)象
* @return 請(qǐng)求結(jié)果
*/
@Override
public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
/**
* 遍歷攔截器進(jìn)行請(qǐng)求處理攒至,請(qǐng)求處理
*
* @param request 請(qǐng)求對(duì)象
*/
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//超出界限拋出異常
if (index >= interceptors.size()) {
throw new AssertionError();
}
//記錄調(diào)用過(guò)的攔截器數(shù)量
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");
}
//創(chuàng)建一個(gè)新的攔截器鏈
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
//位置自增,index + 1躁劣,獲取下一個(gè)攔截器
Interceptor interceptor = interceptors.get(index);
//調(diào)用下一個(gè)攔截器處理請(qǐng)求迫吐,獲取處理結(jié)果
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;
}
}
異步請(qǐng)求流程分析
- 創(chuàng)建Request請(qǐng)求配置類(lèi),調(diào)用client的newCall(request)方法創(chuàng)建Call對(duì)象账忘,調(diào)用Call對(duì)象的enqueue()將請(qǐng)求加入請(qǐng)求隊(duì)列志膀,enqueue(callback)需要傳入Callback回調(diào)對(duì)象。
OkHttpClient client = new OkHttpClient();
//創(chuàng)建請(qǐng)求配置類(lèi)Request
Request request =
new Request.Builder()
.url(url)
.build();
//newCall創(chuàng)建請(qǐng)求對(duì)象Call鳖擒,再通過(guò)enqueue()將請(qǐng)求加入到請(qǐng)求隊(duì)列
Response response = client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
//請(qǐng)求失敗
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//請(qǐng)求成功溉浙,請(qǐng)求響應(yīng)保存再Response中
}
);
- enqueue(callback)方法流程
- 判斷executed標(biāo)志,不允許多次執(zhí)行
- 獲取client的dispatcher請(qǐng)求分發(fā)器蒋荚,調(diào)用enqueue()戳稽,新建一個(gè)AsyncCall()包裝callback回調(diào)對(duì)象。
/**
* 異步執(zhí)行圆裕,將請(qǐng)求交給分發(fā)器隊(duì)列處理
*
* @param responseCallback 請(qǐng)求的回調(diào)對(duì)象
*/
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
//同樣判斷是否執(zhí)行過(guò)了广鳍,不允許多次執(zhí)行
if (executed) {
throw new IllegalStateException("Already Executed");
}
//標(biāo)記
executed = true;
}
captureCallStackTrace();
//回調(diào)事件回調(diào)對(duì)象
eventListener.callStart(this);
//將請(qǐng)求交給分發(fā)器入隊(duì)
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
-
先來(lái)看下dispatcher請(qǐng)求分發(fā)器
-
Dispatcher內(nèi)部有3個(gè)ArrayDeque雙端隊(duì)列荆几,分別為
- 準(zhǔn)備執(zhí)行異步任務(wù)隊(duì)列readyAsyncCalls
- 正在執(zhí)行異步任務(wù)隊(duì)列runningAsyncCalls
- runningSyncCalls同步請(qǐng)求任務(wù)的隊(duì)列
-
enqueue()方法,將包裝了callback的AsyncCall對(duì)象按規(guī)則處理添加不同的隊(duì)列
- runningAsyncCalls正在運(yùn)行的異步任務(wù)的隊(duì)列小于最大請(qǐng)求數(shù)
- runningCallsForHost赊时,異步任務(wù)的host主機(jī)沒(méi)有同時(shí)5個(gè)在允許
-
上面2個(gè)條件
- 滿(mǎn)足條件,將任務(wù)添加到(正在執(zhí)行異步任務(wù)隊(duì)列)runningAsyncCalls竭缝,調(diào)用executorService()獲取線程池執(zhí)行器,將任務(wù)提交給執(zhí)行器馬上執(zhí)行
- 不滿(mǎn)足條件,將任務(wù)添加到(準(zhǔn)備執(zhí)行異步任務(wù)隊(duì)列)readyAsyncCalls,等待任務(wù)被執(zhí)行
-
public final class Dispatcher {
/**
* 準(zhǔn)備執(zhí)行異步任務(wù)的隊(duì)列
*/
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/**
* 正在執(zhí)行異步任務(wù)的隊(duì)列
*/
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/**
* 同步請(qǐng)求任務(wù)的隊(duì)列
*/
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
/**
* 分發(fā)器將異步任務(wù)入隊(duì)
*
* @param call 異步請(qǐng)求對(duì)象
*/
synchronized void enqueue(AsyncCall call) {
//入隊(duì)前限制規(guī)則:
//1、runningAsyncCalls正在運(yùn)行的異步任務(wù)的隊(duì)列小于最大請(qǐng)求數(shù)
//2、runningCallsForHost槐秧,異步任務(wù)的host主機(jī)沒(méi)有同時(shí)5個(gè)在允許
//3、如果上面2個(gè)條件都滿(mǎn)足,那么馬上將任務(wù)排到允許任務(wù)隊(duì)列刘陶,并且馬上執(zhí)行
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//任務(wù)添加到正在執(zhí)行異步任務(wù)的隊(duì)列
runningAsyncCalls.add(call);
//獲取線程池纷责,馬上執(zhí)行曲横,執(zhí)行到AsyncCall時(shí)胳喷,會(huì)回調(diào)AsyncCall的execute()方法尊惰!
executorService().execute(call);
} else {
//不滿(mǎn)足條件鞋诗,添加到準(zhǔn)備執(zhí)行異步任務(wù)的隊(duì)列中
readyAsyncCalls.add(call);
}
}
}
-
接下來(lái)來(lái)分析,AsyncCall類(lèi)
- AsyncCall繼承NamedRunnable類(lèi)
- execute()方法為異步執(zhí)行時(shí)調(diào)用的方法雁刷,和同步一樣炮障,調(diào)用getResponseWithInterceptorChain()責(zé)任鏈方式遍歷攔截器處理Request對(duì)象徘键,返回請(qǐng)求結(jié)果Response它呀。
- 通過(guò)retryAndFollowUpInterceptor.isCanceled()處理任務(wù)被取消的情況谓媒,取消則調(diào)用callback.onFailure()表示請(qǐng)求失敗抢野。
- 沒(méi)有被取消,則為成功扁瓢,調(diào)用callback.onResponse()表示請(qǐng)求成功详恼。
- try-catch處理拋出異常的情況,同樣調(diào)用callback.onFailure()表示請(qǐng)求失敗引几。
- 最后finall塊昧互,調(diào)用分發(fā)器dispatcher的finished方法挽铁,表示任務(wù)完成,繼續(xù)執(zhí)行下一個(gè)任務(wù)敞掘。
/**
* 異步請(qǐng)求叽掘,繼承NamedRunnable類(lèi),NamedRunnable類(lèi)實(shí)現(xiàn)了Runnable接口
*/
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
//省略一些方法...
@Override
protected void execute() {
boolean signalledCallback = false;
try {
//和同步一樣玖雁,被線程池執(zhí)行時(shí)更扁,進(jìn)行責(zé)任鏈處理請(qǐng)求,獲取請(qǐng)求結(jié)果
Response response = getResponseWithInterceptorChain();
//處理被取消的情況
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
//回調(diào)回調(diào)接口對(duì)象
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
//請(qǐng)求成功赫冬,回調(diào)回調(diào)對(duì)象
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 {
//回調(diào)事件回調(diào)接口
eventListener.callFailed(RealCall.this, e);
//回調(diào)接口回調(diào)為失敗
responseCallback.onFailure(RealCall.this, e);
}
} finally {
//結(jié)束請(qǐng)求浓镜,調(diào)用分發(fā)器,讓分發(fā)器繼續(xù)執(zhí)行下一個(gè)任務(wù)
client.dispatcher().finished(this);
}
}
}
-
分析任務(wù)結(jié)束調(diào)用的finished()
- finished()方法有2個(gè)
- finished(AsyncCall)劲厌,異步任務(wù)結(jié)束后調(diào)用膛薛。
- finished(RealCal)同步任務(wù)結(jié)束后調(diào)用。
- 2個(gè)finished()都會(huì)調(diào)用到第三個(gè)參數(shù)的finished补鼻。
- calls哄啄,任務(wù)隊(duì)列,異步任務(wù)傳runningAsyncCalls隊(duì)列风范,同步任務(wù)傳runningSyncCalls隊(duì)列咨跌,
- call,任務(wù)類(lèi)硼婿,異步任務(wù)為AsyncCall锌半,同步任務(wù)為RealCal。
- promoteCalls加酵,代表是否推動(dòng)下一個(gè)異步任務(wù)執(zhí)行拳喻,同步任務(wù)執(zhí)行完就完了,沒(méi)有下一個(gè)所以為false猪腕,異步任務(wù)執(zhí)行完會(huì)有執(zhí)行下一個(gè)異步任務(wù),為true钦勘。
- 先從隊(duì)列中移除任務(wù)(已經(jīng)已經(jīng)完成了)陋葡,再調(diào)用promoteCalls()推動(dòng)下一個(gè)任務(wù)執(zhí)行。
- 獲取同步任務(wù)和異步任務(wù)的數(shù)量彻采,都為0腐缤,則回調(diào)idleCallback表示任務(wù)閑置。
- finished()方法有2個(gè)
/**
* 異步任務(wù)執(zhí)行結(jié)束肛响,會(huì)推動(dòng)下一個(gè)異步任務(wù)執(zhí)行岭粤,因?yàn)榭赡苡械却漠惒饺蝿?wù)在隊(duì)列中等待
*
* @param call 異步請(qǐng)求對(duì)象
*/
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
/**
* 同步任務(wù)執(zhí)行結(jié)束,同步任務(wù)沒(méi)有等待隊(duì)列特笋,所以執(zhí)行完就完了
*/
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
/**
* 任務(wù)結(jié)束處理
*
* @param calls 任務(wù)隊(duì)列
* @param call 異步任務(wù)
* @param promoteCalls 是否推動(dòng)下一個(gè)異步任務(wù)執(zhí)行
*/
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
//從隊(duì)列中移除異步請(qǐng)求
if (!calls.remove(call)) {
throw new AssertionError("Call wasn't in-flight!");
}
//推動(dòng)下一個(gè)異步任務(wù)執(zhí)行
if (promoteCalls) {
promoteCalls();
}
//獲取正在運(yùn)行的異步任務(wù)和同步任務(wù)的總數(shù)量
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
//正在運(yùn)行的異步任務(wù)和同步任務(wù)的數(shù)量之和為0剃浇,則回調(diào)空閑回調(diào)
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
- 分析promoteCalls()方法。由于只有異步任務(wù)才會(huì)調(diào)用promoteCalls(),所以都是異步任務(wù)的處理
- 先判斷runningAsyncCalls執(zhí)行中的異步任務(wù)隊(duì)列的任務(wù)是否已滿(mǎn)虎囚。滿(mǎn)了則不繼續(xù)角塑,等待其他任務(wù)執(zhí)行完來(lái)再來(lái)帶動(dòng)任務(wù)執(zhí)行。
- 再判斷任務(wù)隊(duì)列是否為空淘讥,沒(méi)有任務(wù)則執(zhí)行圃伶,這種情況在最后一個(gè)任務(wù)執(zhí)行完畢后會(huì)出現(xiàn)。
- 遍歷異步任務(wù)隊(duì)列蒲列,獲取每個(gè)異步對(duì)象
- 判斷這個(gè)異步任務(wù)的host窒朋,在當(dāng)前請(qǐng)求的隊(duì)列中,是否小于5個(gè)正在請(qǐng)求蝗岖,小于則開(kāi)始執(zhí)行下一個(gè)異步任務(wù)
- 如果滿(mǎn)足則將任務(wù)添加到runningAsyncCalls正在執(zhí)行異步任務(wù)的隊(duì)列中侥猩,讓執(zhí)行器馬上執(zhí)行
/**
* 推動(dòng)下一個(gè)異步任務(wù)執(zhí)行
*/
private void promoteCalls() {
//正在運(yùn)行的異步任務(wù)隊(duì)列滿(mǎn)了,不開(kāi)始下一個(gè)任務(wù)剪侮,跳出
if (runningAsyncCalls.size() >= maxRequests) {
return; // Already running max capacity.
}
//沒(méi)有任務(wù)執(zhí)行拭宁,跳出
if (readyAsyncCalls.isEmpty()) {
return; // No ready calls to promote.
}
//遍歷準(zhǔn)備開(kāi)始異步任務(wù)的隊(duì)列
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
//下一個(gè)異步任務(wù)
AsyncCall call = i.next();
//判斷這個(gè)異步任務(wù)的host,在當(dāng)前請(qǐng)求的隊(duì)列中瓣俯,是否小于5個(gè)正在請(qǐng)求杰标,小于則開(kāi)始執(zhí)行下一個(gè)異步任務(wù)
if (runningCallsForHost(call) < maxRequestsPerHost) {
//從準(zhǔn)備執(zhí)行異步任務(wù)隊(duì)列中移除任務(wù)
i.remove();
//將任務(wù)添加到正在執(zhí)行的異步任務(wù)
runningAsyncCalls.add(call);
//將任務(wù)交給線程池執(zhí)行
executorService().execute(call);
}
//判斷當(dāng)前運(yùn)行的任務(wù)隊(duì)列是否已滿(mǎn)
if (runningAsyncCalls.size() >= maxRequests) {
return; // Reached max capacity.
}
}
}
- 最后來(lái)看下NamedRunnable類(lèi)
- NamedRunnable實(shí)現(xiàn)了Runnable接口,所以他可以被線程池執(zhí)行器執(zhí)行彩匕。
- 使用模板模式腔剂,復(fù)寫(xiě)run()方法,調(diào)用定義的抽象execute()執(zhí)行方法驼仪,讓子類(lèi)重寫(xiě)掸犬,同時(shí)將run()方法設(shè)置為final防止被重寫(xiě)流程。
- 統(tǒng)一設(shè)置線程名稱(chēng)绪爸。
/**
* 實(shí)現(xiàn)了Runnable接口湾碎,給每個(gè)異步任務(wù)定義線程名
*/
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
/**
* 任務(wù)run()方法,為被子線程執(zhí)行的回調(diào)方法奠货,設(shè)置為final介褥,不允許子類(lèi)復(fù)寫(xiě)修改,并提供execute抽象方法递惋,模板模式處理柔滔,定義統(tǒng)一行為
*/
@Override
public final void run() {
//配置線程名
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
//調(diào)用定義execute抽象方法
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
/**
* 將run()方法轉(zhuǎn)化為抽象的execute給子類(lèi)復(fù)寫(xiě),執(zhí)行異步任務(wù)
*/
protected abstract void execute();
}
攔截器分析
主要分析的攔截器:
- BridgeInterceptor:對(duì)請(qǐng)求添加一些必要的Header萍虽,接受響應(yīng)時(shí)移除掉一些Header的攔截器
- CacheInterceptor:緩存攔截器睛廊,對(duì)請(qǐng)求前本地緩存查詢(xún)和攔截,對(duì)請(qǐng)求結(jié)果進(jìn)行本地緩存
- ConnectInterceptor:連接攔截器杉编,負(fù)責(zé)請(qǐng)求和服務(wù)器建立連接
- BridgeInterceptor超全,對(duì)請(qǐng)求添加一些必要的Header咆霜,接受響應(yīng)時(shí)移除掉一些Header的攔截器
public final class BridgeInterceptor implements Interceptor {
private final CookieJar cookieJar;
public BridgeInterceptor(CookieJar cookieJar) {
this.cookieJar = cookieJar;
}
/**
* 將配置的Request對(duì)象中的Header配置整理一遍重新創(chuàng)建一個(gè)Request
*
* @param chain 攔截器鏈
* @return 請(qǐng)求結(jié)果
*/
@Override
public Response intercept(Chain chain) throws IOException {
//獲取原始配置
Request userRequest = chain.request();
//新建Request配置
Request.Builder requestBuilder = userRequest.newBuilder();
//獲取Body
RequestBody body = userRequest.body();
if (body != null) {
MediaType contentType = body.contentType();
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString());
}
long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {
requestBuilder.header("Transfer-Encoding", "chunked");
requestBuilder.removeHeader("Content-Length");
}
}
//配置默認(rèn)Host
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}
//配置默認(rèn)Connection為保持連接
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
//添加透明的Gzip壓縮
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
//如果有配置Cookie,添加Cookie到Header
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
//配置默認(rèn)的UA
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
//生成新的Request卵迂,執(zhí)行下一個(gè)攔截器獲取響應(yīng)結(jié)果
Response networkResponse = chain.proceed(requestBuilder.build());
//處理請(qǐng)求頭
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
//重新生成響應(yīng)配置
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
//響應(yīng)報(bào)文裕便,移除一些Header,壓縮響應(yīng)報(bào)文
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);
String contentType = networkResponse.header("Content-Type");
responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
}
//重新生成響應(yīng)報(bào)文
return responseBuilder.build();
}
/**
* Returns a 'Cookie' HTTP request header with all cookies, like {@code a=b; c=d}.
*/
private String cookieHeader(List<Cookie> cookies) {
StringBuilder cookieHeader = new StringBuilder();
for (int i = 0, size = cookies.size(); i < size; i++) {
if (i > 0) {
cookieHeader.append("; ");
}
Cookie cookie = cookies.get(i);
cookieHeader.append(cookie.name()).append('=').append(cookie.value());
}
return cookieHeader.toString();
}
}
- CacheInterceptor见咒,緩存攔截器偿衰,對(duì)請(qǐng)求前本地緩存查詢(xún)和攔截,對(duì)請(qǐng)求結(jié)果進(jìn)行本地緩存
public final class CacheInterceptor implements Interceptor {
final InternalCache cache;
public CacheInterceptor(InternalCache cache) {
this.cache = cache;
}
/**
* 緩存攔截器
*
* @param chain 攔截器鏈
* @return 請(qǐng)求結(jié)果
*/
@Override
public Response intercept(Chain chain) throws IOException {
//獲取緩存容器中請(qǐng)求的緩存改览,候選緩存
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
long now = System.currentTimeMillis();
//緩存策略工廠下翎,傳入網(wǎng)絡(luò)請(qǐng)求的Request和緩存的響應(yīng),決定緩存策略
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
if (cache != null) {
cache.trackResponse(strategy);
}
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
}
//請(qǐng)求失敗宝当、緩存也失敗视事,返回失敗的結(jié)果
if (networkRequest == null && cacheResponse == null) {
return new Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(Util.EMPTY_RESPONSE)
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
}
//緩存不為空,網(wǎng)絡(luò)請(qǐng)求也不需要庆揩,則我們緩存命中
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
//緩存不命中俐东,要請(qǐng)求網(wǎng)絡(luò),調(diào)用下一個(gè)攔截器去請(qǐng)求订晌,并獲取結(jié)果
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());
}
}
//本地緩存是存在的虏辫,將本地緩存和網(wǎng)絡(luò)請(qǐng)求結(jié)果比較,決定是否將這個(gè)網(wǎng)絡(luò)請(qǐng)求結(jié)果緩存到本地
if (cacheResponse != null) {
if (networkResponse.code() == HTTP_NOT_MODIFIED) {
Response response = cacheResponse.newBuilder()
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.sentRequestAtMillis(networkResponse.sentRequestAtMillis())
.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
networkResponse.body().close();
// Update the cache after combining headers but before stripping the
// Content-Encoding header (as performed by initContentStream()).
cache.trackConditionalCacheHit();
//以本次網(wǎng)絡(luò)請(qǐng)求結(jié)果锈拨,更新本地緩存
cache.update(cacheResponse, response);
return response;
} else {
closeQuietly(cacheResponse.body());
}
}
//重新構(gòu)造輸出結(jié)果
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
if (cache != null) {
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
//本地緩存不存在砌庄,保存本次網(wǎng)絡(luò)請(qǐng)求的緩存到本地
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
//如果緩存是無(wú)效的,則移除緩存
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
cache.remove(networkRequest);
} catch (IOException ignored) {
// The cache cannot be written.
}
}
}
return response;
}
//...省略其他代碼
}
- ConnectInterceptor奕枢,連接攔截器娄昆,負(fù)責(zé)請(qǐng)求和服務(wù)器建立連接
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;
Request request = realChain.request();
//StreamAllocation將連接創(chuàng)建、連接管理的封裝類(lèi)
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是對(duì) HTTP 協(xié)議操作的抽象缝彬,有兩個(gè)實(shí)現(xiàn):Http1Codec和Http2Codec萌焰,顧名思義,它們分別對(duì)應(yīng) HTTP/1.1 和 HTTP/2 版本的實(shí)現(xiàn)谷浅。在這個(gè)方法的內(nèi)部實(shí)現(xiàn)連接池的復(fù)用處理
//開(kāi)始連接
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
//調(diào)用下一個(gè)攔截器
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
}
總結(jié)
本篇分析了OkHttp3的請(qǐng)求流程和攔截器杆怕,作為最為核心的就是攔截器部分,將每部分的附加和處理都分類(lèi)到不同的攔截器進(jìn)行解耦壳贪。
異步流程通過(guò)Dispatch分發(fā)器將任務(wù)提交給線程池,每個(gè)任務(wù)執(zhí)行完后通知分發(fā)器寝杖,分發(fā)器再繼續(xù)尋找下一個(gè)異步任務(wù)進(jìn)行執(zhí)行违施。
橋接攔截器對(duì)Request做Header補(bǔ)充,并且自動(dòng)處理Cookie瑟幕。
緩存攔截器磕蒲,先對(duì)Request對(duì)象從本地獲取緩存留潦,緩存可用時(shí)則使用,否則調(diào)用下一個(gè)攔截器進(jìn)行請(qǐng)求辣往,請(qǐng)求成功后返回兔院,獲取到結(jié)果后,再緩存到本地站削。