Call和RealCall
經(jīng)過上面的初始化之后 okhttpClient 調用public Call newCall(Request request)
方法去構建一個Call畏纲,
@Override
public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
可以看到 真實的Call是RealCall ,get知識點 一般來說邑茄,一個組織或者個人的代碼風格是差不多的
這里面Call的實現(xiàn)類是RealCall十兢,其他的應該也是Real開頭的。
這里我們發(fā)現(xiàn)他把OkHttpClient和Reques傳了過去,他的構造方法是
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
//重試和跟進攔截器
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
// TODO(jwilson): this is unsafe publication and not threadsafe.
// 這是不安全的發(fā)布,不是線程安全的议双。
this.eventListener = eventListenerFactory.create(this);
}
這里面比較面生的是的是RetryAndFollowUpInterceptor 按照字面意思重試和跟進攔截器 進去大概看一下
/**
* This interceptor recovers from failures and follows redirects as necessary. It may throw an
* {@link IOException} if the call was canceled.
* 這個攔截器從故障中恢復,并根據(jù)需要遵循重定向捉片。如果呼叫被取消平痰,它可能會拋出IOException。
*/
public final class RetryAndFollowUpInterceptor implements Interceptor {
/**
* How many redirects and auth challenges should we attempt? Chrome follows 21 redirects; Firefox,
* curl, and wget follow 20; Safari follows 16; and HTTP/1.0 recommends 5.
* 我們應該嘗試多少次重定向和認證挑戰(zhàn)伍纫? Chrome遵循21次重定向; Firefox宗雇,curl和wget遵循20; Safari遵循16; HTTP / 1.0建議5。
*/
private static final int MAX_FOLLOW_UPS = 20;
private final OkHttpClient client;
private final boolean forWebSocket;
private StreamAllocation streamAllocation;
private Object callStackTrace;
private volatile boolean canceled;
public RetryAndFollowUpInterceptor(OkHttpClient client, boolean forWebSocket) {
this.client = client;
this.forWebSocket = forWebSocket;
}
(....此處省略以后的代碼)
果然和字面意思一樣莹规,這面看參數(shù)的話最大支持20次的重定向赔蒲。后面的暫時不需要看 等用到的時候再看也不遲,避免陷入之間樹木不見森林的坑
后面又用工廠方法創(chuàng)建了一個EventListener
的類访惜,看字面意思就是時間的監(jiān)聽類看里面的方法
Factory
fetchStart
dnsStart
dnsEnd
connectStart
secureConnectStart
secureConnectEnd
connectEnd
requestHeadersStart
requestHeadersEnd
requestBodyStart
requestBodyEnd
responseHeadersStart
responseHeadersEnd
responseBodyStart
responseBodyEnd
fetchEnd
通過這個事件我們大致能看出來OkHttp請求的流程嘹履,然后回到RealCall ,之后調用的是一個execute或者是enqueue 我們在Android項目里由于主線程是不允許有網(wǎng)絡請求的债热,所以我們先來搞enqueue,話不多說幼苛,進去看
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//捕獲呼叫堆棧跟蹤
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
Already Executed 這個異常大家在平時用的時候應該偶爾會碰到窒篱,原因看到了吧。當你的這個請求應在運行的時候你在去調用的時候就異常了
然后第二個是捕獲呼叫堆棧跟蹤器舶沿,這個就忽略掉墙杯,看真正的重頭戲
前方高能預警,提起精神看
Dispatcher
相關的更詳細的分析在第五篇 OkHttp的請求調度分析
調用的OkHttpClient 的dispatcher的enqueue方法括荡,dispatcher的初始化是在OkHttpClient的Builder里面 看上面的代碼 是直接new 了一個 Dispatcher 高镐,我們去dispatcher里看
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
/** Executes calls. Created lazily. */
private ExecutorService executorService;
/** Ready async calls in the order they'll be run. 按照他們將要運行的順序進行準備就緒的異步調用 */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. 運行異步調用包括尚未完成的取消請求*/
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. 運行同步調用包括尚未完成的取消呼叫*/
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
(....此處省略N行代碼)
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
}
我們看到他的構造函數(shù)就是一個空的 然后全局變量的話有個線程池,和三個雙端隊列 有可能有同學不知道Deque是什么畸冲,deque 即雙端隊列嫉髓。是一種具有隊列和棧的性質的數(shù)據(jù)結構。雙端隊列中的元素可以從兩端彈出邑闲,其限定插入和刪除操作在表的兩端進行算行。
我們看到enqueue里面就是操作運行異步調用包括尚未完成的取消請求的runningAsyncCalls,他的判斷條件是:
1.當前隊列里面的請求數(shù)量小于最大請求數(shù)也就是64
2.當前隊列里面的鏈接的總host數(shù)量小于最大請求Host數(shù)
如果條件成立就添加到這個隊列里面苫耸,否則的話就添加到readyAsyncCalls里州邢,也就是按照他們將要運行的順序進行準備就緒的異步調用的隊列
加入到運行隊列里后,執(zhí)行executorService().execute(call);
方法這個方法就是個new出了一個線程池褪子,然后執(zhí)行
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
可能關于線程池的一些東西大家不是特別清楚 這里稍微解釋一下量淌,首先是他的構造函數(shù)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)
corePoolSize: 線程池維護線程的最少數(shù)量
maximumPoolSize:線程池維護線程的最大數(shù)量
keepAliveTime: 線程池維護線程所允許的空閑時間
unit: 線程池維護線程所允許的空閑時間的單位
workQueue: 線程池所使用的緩沖隊列
handler: 線程池對拒絕任務的處理策略
上面的SynchronousQueue可能一般同學看的不是特別熟悉這里解釋一下:
SynchronousQueue是一個沒有數(shù)據(jù)緩沖的BlockingQueue骗村,生產(chǎn)者線程對其的插入操作put必須等待消費者的移除操作take,反過來也一樣呀枢。
SynchronousQueue的一個使用場景的典型就是在線程池里叙身。Executors.newCachedThreadPool()就使用了SynchronousQueue,這個線程池根據(jù)需要(新任務到來時)創(chuàng)建新的線程硫狞,如果有空閑線程則會重復使用信轿,線程空閑了60秒后會被回收。執(zhí)行是調用execute方法残吩。
峰回路轉 财忽,回到ReallCall的enqueue里面
這里執(zhí)行的正式AsyncCall,new AsyncCall(responseCallback)
AsyncCalls是RealCall的一個內部類泣侮,繼承NamedRunnable即彪,NamedRunnable是一個實現(xiàn)了Runnable接口的抽象類,
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
這里他做了兩件事
- 給當前線程設設置了個名字
- 新增了一個抽象方法execute
把握住這兩個 再來看AsyncCall
AsyncCall
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
//命名規(guī)則 OkHttp+協(xié)議名+域名
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 {
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 {
//調用dispatcer的finshed方法活尊,(重要隶校,在下文的請求調度分析會將)
client.dispatcher().finished(this);
}
}
}
上面比較重要的是這一句
Response response = getResponseWithInterceptorChain();
如果重試和跟進攔截器沒有被取消的話,返回請求成功調用 responseCallback.onResponse蛹锰,如果中間有什么異常的話調用responseCallback.onFailure(RealCall.this, e);
getResponseWithInterceptorChain()
這個方法非常重要深胳,是整個OkHttp請求的核心,他是組裝了一系列的攔截鏈铜犬,進行鏈式調用舞终,最后返回組裝的請求結果
/*一共五個攔截器 包括
* RetryAndFollowUpInterceptor 重試和跟進攔截器
* BridgeInterceptor 橋攔截器
* CacheInterceptor 緩存攔截器
* ConnectInterceptor 鏈接攔截器
* CallServerInterceptor 呼叫服務攔截器
*
* RealInterceptorChain 實際攔截鏈
* */
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);
}
接下來 我們來走進這些請求鏈的世界癣猾,去分析整個OkHttp請求的具體