Okhttp原始碼閱讀(一)——一個請求是怎麼發生的

SamanLan發表於2017-12-13

本次閱讀的okhttp原始碼版本為3.7.0

我讀原始碼的習慣是從入口開始看起,所以我們首先看看一次使用okhttp請求的程式碼流程

OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
  .get()
  .url("http://www.baidu.com")
  .build();
okHttpClient.newCall(request).enqueue(new Callback() {
  @Override
  public void onFailure(Call call, IOException e) {}
  @Override
  public void onResponse(Call call, Response response) throws IOException {}
});
複製程式碼

可以看到,一次請求最小元素是newCall()裡面的Call。

Call原始碼擷取
可以看到Call只是一個介面而已;需要注意的點已經標紅了

  • 一個Call,它不能被執行兩次(即enqueue或execute只能呼叫一次)
  • 一個Call可以取消,但不是一定能取消,假如請求已完成就不能取消了

具體是為什麼繼續往下看。 在原始碼裡面可以看到RealCall是繼承Call,那麼來看一下RealCall的實現

RealCall實現
可以看到每次進行 executeenqueue 的時候都會上鎖然後通過判斷是否執行過該 Call 故重複呼叫會丟擲異常。 那麼接下來我們先看 execute (同步請求),在程式碼中可以看到首先執行了client.dispatcher().executed(call)這個方法,在最後執行了client.dispatcher().finished(this);這個方法,那Dispatcher是什麼? Dispatcher是okhttp中的排程器,請求的執行政策
Dispatcher

Dispatcher中的execute方法
client.dispatcher().executed(call)這個方法比較簡單,只是單純的往同步請求佇列新增而已

Dispatcher中的finish方法
這裡如果是同步就是簡單的往同步請求佇列移除

接著我們來看最關鍵的 getResponseWithInterceptorChain()

getResponseWithInterceptorChain

建構函式
在其中,這個index起到至關重要的作用。

最叼的層層呼叫,層層返回

所以由上圖我們得知最後會優先執行了攔截器鏈最後的一個攔截器(即上方的CallServerInterceptor攔截器,這個攔截器會進行真正的網路請求),然後再一層層將結果返回給各個攔截器處理。

最後我們再看看非同步請求,執行了client.dispatcher().enqueue(new AsyncCall(responseCallback));

Dispatcher中的execute方法
client.dispatcher().executed(call)這個方法比較簡單,首先判斷正在執行的請求數是否小於設定值(預設值)且與該請求相同主機的請求是否小於設定值(預設值),是則加入執行緒池中並新增進正在請求的佇列;否則加入待請求的佇列。 那看看傳進去的AsyncCall

AsyncCall
可以看到基本和同步請求幾乎是一樣的,相當於把同步請求放進runnable裡面然後多了回撥~,~。 好了,本次閱讀到此告一段落

相關文章