OkHttp源碼解讀總結(三)--->OkHttp同步請求源碼解析

OkHttp源碼解讀總結(三)—>OkHttp同步請求源碼解析

標籤(空格分隔): OkHttp源碼 學習筆記


前言

  • 以下的相關知識總結是通過慕課網的相關學習和自己的相關看法,如果有需要的可以去查看一下慕課網的相關教學,感覺還可以。

第一步創建的OkHttpClient客戶端

創建這個OkHttpClient並設置相關的參數,需要用到他的內部類的Builder的build()方法。首先我們看下這個builder的構造方法(無參的構造方法)

 public Builder() {

      //主要的幾個參數

      //dispatcher對象  http請求的分發器 主要是作用於異步請求是需要直接處理還是進行緩存等待(緩存)
      dispatcher = new Dispatcher();

      //連接池   客戶端和服務器之間的可以看做一個Connection  而每一個Connection我們都會把他放在這個連接池中  進行統一管理  (1)如果URL相同的時候可以選擇複用  (2)進行相關設置,是保持連接還是選擇以後複用管理
      connectionPool = new ConnectionPool();

      //默認的超時相關時間
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
    }

第二步創建Request請求報文信息類

這個Request對象的創建也是一個建造者模式來構建的。通過鏈式調用指定請求方法,指定頭部,請求參數等等設置

 //這個比較簡單  
 public Builder() {
      設置請求方法爲GET請求
      this.method = "GET";
      //創建了一個Headers的內部類 用於保存頭部信息
      this.headers = new Headers.Builder();
    }

 public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      //可以看到這個build方法就是把當前的Builder對象傳遞到Request裏面  創建Request對象  也就是說 通過這個build()方法之後,就能把我們已經配置好的Builder的中的請求方式,請求地址,頭部 都賦值給我們的Request對象
      return new Request(this);
    }


    所以可以看下Request這個構造方法  我們可以看到在構造方法中,通過傳遞進來的Builder這個實例來進行相關變量的賦值

     Request(Builder builder) {
    this.url = builder.url; //網絡地址
    this.method = builder.method; //請求方式
    this.headers = builder.headers.build(); //頭部
    this.body = builder.body;  //body
    this.tag = builder.tag != null ? builder.tag : this;
  }

3、創建Http請求的實際Call對象

 Call requestCall = getOkHttpClient().newCall(request);

  @Override 
  public Call newCall(Request request) {
    //因爲Call是一個接口   他的實際操作都是在他的實現類中進行 也就是RealCall這個實現類
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

Call請求的實現類RealCall

 static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    //創建了實現類的對象  通過okhttpclient  request
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
  }


 RealCall的構造方法

  private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    //持有傳入進來的兩個實例
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    //創建一個重定向攔截器  以後會進行講解
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

  不管是同步還是異步,都是通過newCall()這個方法創建的RealCall對象來進行相應的操作

4、execute()方法進行同步請求

  Response response = requestCall.execute();

  RealCall的實現類覆寫的這個execute()方法

   @Override public Response execute() throws IOException {
    //同步
    synchronized (this) {
      //判斷這個是否被執行過  一個http請求只能執行一次  如果已經執行了 那麼就會拋出異常  
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //捕捉異常堆棧信息
    captureCallStackTrace();
    //監聽事件開啓
    eventListener.callStart(this);
    try {
      //核心代碼
      client.dispatcher().executed(this);

      //當把請求call放置到同步請求隊列當中  進行請求之後  我們通過getResponseWithInterceptorChain()這個方法來獲取相應Response  這個之後再總結(攔截器)
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      //結束
      client.dispatcher().finished(this);


    }
  }

client.dispatcher()

 public Dispatcher dispatcher() {
    return dispatcher;
  }

client.dispatcher().executed(this)

 /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();  //這個是在Dispatcher類中定義的 同步請求隊列  可以看出 還定義的有
   /** 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<>();

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

補充
image.png

client.dispatcher().finished(this)方法;

  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) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      //同步不走  因爲始終傳入的是false
      if (promoteCalls) promoteCalls();
      //計算目前還在進行的請求
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }
    //如果正在請求的數爲0  沒有可運行的請求   並且idleCallback不爲空
    if (runningCallsCount == 0 && idleCallback != null) {   
      //run方法
      idleCallback.run();
    }
  }

  //返回正在執行的異步和同步請求總和
   public synchronized int runningCallsCount() {
    return runningAsyncCalls.size() + runningSyncCalls.size();
  }

可以看出這個Dispatcher分發器在同步請求中做的很簡單,那就是保存和移除同步請求。對於異步請求,Dispatcher就需要做的好多工作了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章