OkHttp原始碼流程分析
阿新 • • 發佈:2018-11-21
OkHttpClient okHttpClient = new OkHttpClient.Builder().build(); Request request = new Request.Builder().build(); Call newCall = okHttpClient.newCall(request); //同步請求 //Response response = newCall.execute(); //非同步請求 newCall.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { } });
- 非同步請求介面的Callback中的成功失敗介面回撥是執行在子執行緒
execute()總結
public Response execute() throws IOException { synchronized (this) { //判斷當前call是否執行過,是的話拋異常 if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); eventListener.callStart(this); try { //將當前call新增到Dispatcher正在執行的任務佇列 client.dispatcher().executed(this); //通過一系列攔截器鏈做網路請求,拿到response Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } catch (IOException e) { eventListener.callFailed(this, e); throw e; } finally { //從正在執行的任務佇列中移除當前call client.dispatcher().finished(this); } }
- 判斷當前call是否執行過,是的話拋異常
- 將當前call新增到Dispatcher正在執行的任務佇列
- 通過一系列攔截器鏈做網路請求,拿到response
- 從正在執行的任務佇列中移除當前call
非同步enqueue()總結
> RealCall類enqueue()方法 public void enqueue(Callback responseCallback) { synchronized (this) { //判斷當前call是否執行過,是的話拋異常 if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); eventListener.callStart(this); client.dispatcher().enqueue(new AsyncCall(responseCallback)); }
-
判斷當前call是否執行過,是的話拋異常
-
將callBack封裝成一個AsyncCall物件
- AsyncCall繼承NamedRunnable,定義在RealCall中的內部類
- NamedRunnable是Runnable的一個實現類,Runnable的run()方法內部會呼叫到自己類中的一個抽象方法execute(),最終實現在AsyncCall中
> AsyncCall類execute()方法具體實現 protected void execute() { boolean signalledCallback = false; try { //通過一系列攔截器鏈做網路請求,拿到response Response response = getResponseWithInterceptorChain(); //通過判斷重定向重試攔截器是否被取消了,是的話就呼叫responseCallback.onFailure() 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 { //發生異常也會呼叫失敗回撥 eventListener.callFailed(RealCall.this, e); responseCallback.onFailure(RealCall.this, e); } } finally { //將當前請求call物件從正在執行任務佇列中移除 client.dispatcher().finished(this); } }
-
呼叫client.dispatcher().enqueue()
> Dispatcher類enqueue()方法 //判斷正在執行非同步任務佇列大小是否小於最大請求數(64)並且通過runningCallsForHost()方法獲取到正在執行的非同步任務佇列中和當前call所要請求的主機一樣的呼叫數來判斷是否小於最大請求主機數(5) //如果滿足上述條件 則將當前call新增到正在執行非同步任務佇列中,否則新增到等待非同步任務佇列 synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { //新增到非同步任務佇列 runningAsyncCalls.add(call); //開啟執行緒池執行當前call //executorService()方法內部會判斷執行緒池是否已經建立,是的話直接返回,否的話建立執行緒池 //execute() 將來某個時候執行給定的任務,任務可以在新執行緒或現有池中已存在的執行緒執行 //其實就是把AsyncCall(執行緒的實現類)物件放到執行緒池中,最後真正執行的就是AsyncCall物件的execute()方法 executorService().execute(call); } else { //新增到非同步等待任務佇列 readyAsyncCalls.add(call); } }
Dispatcher
-
什麼是Dispatcher?
dispatcher的作用是維護請求的狀態,並維護一個執行緒池,用於執行請求
-
Dispatcher的非同步請求為什麼要維護兩個任務佇列?
Dispatcher 生產者
ExecutorService 消費者池
- runningAsyncCalls 正在執行非同步請求佇列,包含沒有執行完的請求但已經被取消了
- readyAsyncCalls 就緒狀態非同步請求佇列
- executorService 執行請求的執行緒池
-
executorService()
public synchronized ExecutorService executorService() { if (executorService == null) { //corePoolSize:0 核心執行緒數.0的話就表示在空閒一段時間(keepAliveTime)後,會將全部執行緒銷燬 //maximumPoolSize:Integer.MAX_VALUE 執行緒池允許建立最大執行緒數;理論上設定MAX_VALUE可以無限擴充建立執行緒,由於OKHttp有maxRequests(64)限制,實際並不能無限建立執行緒 //keepAliveTime:60 空閒執行緒最大存活時間.當我們的執行緒數大於核心執行緒數,多餘的空閒執行緒最大存活時間 //3個引數含義:當執行緒池中任務執行完畢之後,會在60秒之後相繼關閉所有空閒執行緒 executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false)); } return executorService; }
-
移除任務call
同步請求和非同步請求在拿到Response之後都會呼叫finished()方法
> 以下方法全是在Dispatcher類中 //非同步請求 void finished(AsyncCall call) { finished(runningAsyncCalls, call, true); } //同步請求 void finished(RealCall call) { finished(runningSyncCalls, call, false); } private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) { int runningCallsCount; Runnable idleCallback; synchronized (this) { //從當前任務佇列中移除當前call if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!"); //調整非同步請求任務佇列 只有非同步請求才會執行promoteCalls() if (promoteCalls) promoteCalls(); //重新計算正在執行任務數:非同步請求+同步請求任務數量之和 runningCallsCount = runningCallsCount(); idleCallback = this.idleCallback; } if (runningCallsCount == 0 && idleCallback != null) { idleCallback.run(); } } /** 非同步請求佇列重新排程.從等待佇列中移除一個任務,新增到正在執行非同步佇列中 */ private void promoteCalls() { if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity. if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote. for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) { AsyncCall call = i.next(); if (runningCallsForHost(call) < maxRequestsPerHost) { i.remove(); runningAsyncCalls.add(call); executorService().execute(call); } //如果正在執行非同步佇列中數量大於等於最大請求數(64),直接結束排程 if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity. } }
攔截器
攔截器是OkHttp中提供一種強大機制,它可以實現網路監聽、請求以及響應重寫、請求失敗重試等功能
-
RetryAndFollowUpInterceptor
重試,失敗重定向攔截器
- 建立StreamAllocation物件
- 呼叫RealInterceptorChain.proceed()方法進行網路請求
- 根據異常結果獲取響應結果判斷是否要重新請求
- 呼叫下一個攔截器,對Response進行處理
-
BridgeInterceptor
橋接適配攔截器,處理請求缺少必要的http請求頭相關資訊
- 負責將使用者構建的一個Request請求轉化為能夠進行網路訪問的請求
- 將這個符合網路請求的Request進行網路請求
- 將網路請求回來的響應Response轉化為使用者可用的Response
-
CacheInterceptor
快取攔截器,通過DiskLRUCache實現快取存取,OkHttp內部維護清理執行緒池,會自動清理快取檔案
-
ConnectInterceptor
連線攔截器,建立可用的連線
- ConnectInterceptor獲取Interceptor傳遞過來的StreamAllocation,streamAllocation.newStream()
- 將剛才建立用於網路IO的RealConnection物件,以及對於與伺服器互動最為關鍵的HttpCodec等物件傳遞後面的Interceptor
newStream()總結
- 獲取到一個RealConnection
- 選擇不同的連結方式
-
CallServerInterceptor
- 將http請求寫入到網路的IO流當中,從網路io流中讀取返回資訊