天天看點

OKHttp源碼解析(一)之OKHttp源碼執行流程

前言

Android開發中,常用的第三方網絡請求架構有Retrofit,OKHttp,Volley。最近重構項目架構采用的是Kotlin + Retrofit + RxJava,Retrofit的底層實作就是OKHttp實作。本篇文章介紹OKHttp源碼執行過程。

請求示例

1.Gradle引入

GRADLE

compile 'com.squareup.okhttp3:okhttp:(insert latest version)'
           

2.GET請求

OkHttpClient client = new OkHttpClient();

String run(String url) throws IOException {
  Request request = new Request.Builder()
      .url(url)
      .build();

  Response response = client.newCall(request).execute();
  return response.body().string();
}
           

4.OKHttp請求流程

OKHttp源碼解析(一)之OKHttp源碼執行流程

5.源碼執行流程

根據上面的執行流程和GET請求,我們來看下源碼是如何是如何實作的。

OKHttpClient是什麼?

網絡請求的工廠,用于發送HTTP請求并且讀取響應的一個類。通過new OKHttpClient()方式來建立一個單一的HTTP用戶端。我們來分析一波OKHttpClient的源碼。

我們來看下OKHttpClient類的newCall(request)方法做了啥。

/**
   * Prepares the {@code request} to be executed at some point in the future.
   * 準備request網絡請求 在将來某個時候執行。
   */
  @Override public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
  }
           

網絡請求Request的建構很簡單。我們的Request類中通過建造者(Builder)模式,将請求的Url(請求位址連結),Method(請求方法),Headers(請求頭),Body(請求體)等資訊添加到Request對象中。我們可以看到new Call(request)方法很簡單傳回了RealCall的執行個體。接下來我們進入RealCall類中一探究竟。

RealCall 實作了Call接口,在Call中我們定義了請求方法。

Call接口:

/**
   * 請求方法
   */
  Request request();

 /**
   * 同步請求方法
   */
  Response execute() throws IOException;

  /**
   * 異步請求方法
   */
  void enqueue(Callback responseCallback);

  /**
   * 取消請求調用
   */
  void cancel();

  /**
   * 判斷請求調用是否執行 
   */
  boolean isExecuted();

  /**
   * 判斷請求調用是否取消
   */
  boolean isCanceled();

  /**
   * 克隆一個請求調用
   */
  Call clone();
           

RealCall.構造函數

RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
    //傳入的OKHttpClient對象
    this.client = client;
    //傳入的Request請求對象
    this.originalRequest = originalRequest;
    //是否是webSocket請求,這裡預設false
    this.forWebSocket = forWebSocket;
    //一個可以重故障中恢複的攔截器(出鏡很高-->攔截器)
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);

  }
           

RealCall.excute()

@Override public Response execute() throws IOException {
    //1.目前請求已經執行過 抛異常
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //2.捕獲目前請求堆棧跟蹤變化
    captureCallStackTrace();
    try {
      //3.執行同步網絡請求操作(**Dispatcher分發器是什麼?**)
      client.dispatcher().executed(this);
      //4.擷取請求傳回的結果
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      //5.結束目前網絡請求
      client.dispatcher().finished(this);
    }
  }
           

Dispatcher分發器是什麼?

執行異步請求時的政策?通俗點來說,我們有很多的異步請求,請求的執行順序,執行規則都是由分發器決定的,每個分發器的内部有個ThreadPoolExecutor,這是線程池的核心類。作用是什麼呢?當然是将線程進行複用,每個請求需要一個線程去執行,當執行完一個請求任務結束之後,重新建立新的線程太消耗性能。不需要在重新建立一個新的線程去執行下一個任務。我們先有這樣一個概念,Java的線程池是個很”重”的知識點,改天我們将他’扒個幹淨’。接下來我們看下Dispatcher類中的請求方法。

同步:

/** 運作同步調用。包括尚未結束的已取消呼叫 */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

  /** 将我們請求添加到同步請求隊列中 */
  synchronized void executed(RealCall call) {
     runningSyncCalls.add(call);
  }
           

異步:

/** 運作異步調用。包括尚未結束的已取消呼叫 */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

 synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
           

每一個請求都建立了一個RealCall執行個體,而異步請求AsyncCall 是RealCall的内部類,每個Call都需要一個線程去任務,執行Call的過程其實就是執行線程的excute()過程。當Dispatcher接收到一個請求時,Dispatcher負責在其内部維護的線程池中找出空閑的線程去執行其execute()方法。

Response傳回

RealCall類中執行請求動作後就通過 Response result = getResponseWithInterceptorChain();傳回了服務端響應的結果。

Response getResponseWithInterceptorChain() throws IOException {
    // 建立一個完整的攔截器堆棧
    List<Interceptor> interceptors = new ArrayList<>();

    interceptors.addAll(client.interceptors());

    //1.暫且叫它 -->可恢複的攔截器,根據需要進行重定向
    interceptors.add(retryAndFollowUpInterceptor);

    //2.橋接攔截器
    interceptors.add(new BridgeInterceptor(client.cookieJar()));

    //3.請求是從内部緩存中發出,緩存攔截器将傳回寫入到響應緩存中和此請求對應
    interceptors.add(new CacheInterceptor(client.internalCache()));

    //4.打開用戶端與目标伺服器的連接配接-->連接配接伺服器
    interceptors.add(new ConnectInterceptor(client));

    //5.攔截器鍊中最後一個攔截器,對伺服器進行請求呼叫
    interceptors.add(new CallServerInterceptor(forWebSocket));

    //6.Boss是我:承載整個攔截器鍊的具體攔截器鍊:所有應用程式,攔截器、OkHttp核心、所有網絡攔截器,最後是網絡調用者。
    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, , originalRequest);
    return chain.proceed(originalRequest);
  }
           

核心方法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 + , request);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    return response;
  }
           

結尾

本篇介紹了OKHttp的源碼執行的流程,下篇将對OKHttp網絡請求究竟發生了什麼?如何得到伺服器傳回值?以及對OKHttp的核心攔截器将會作詳細的介紹。