02.OkHttp重要類說明

目錄介紹

  • 01.有哪些重要的類
  • 02.OKHttpClient類
  • 03.Request和Response類
  • 04.Call接口類說明
  • 05.RealCall類說明
  • 06.Dispatcher類說明
  • 07.主要流程圖

01.有哪些重要的類

  • OKHttpClient類
  • Request類和Response類
  • Call類和RealCall類
  • Dispatcher類

02.OKHttpClient類說明

  • 1、裏面包含了很多對象,其實OKhttp的很多功能模塊都包裝進這個類,讓這個類單獨提供對外的API,這種外觀模式的設計十分的優雅。外觀模式。
  • 2、而內部模塊比較多,就使用了Builder模式(建造器模式)。Builder模式(建造器模式)
  • 3、它的方法只有一個:newCall.返回一個Call對象(一個準備好了的可以執行和取消的請求)。

03.Request和Response類

  • Request類說明
    • Request抽象成請求數據
    • Request包括Headers和RequestBody,而RequestBody是abstract的,他的子類是有FormBody(表單提交的)和MultipartBody(文件上傳),分別對應了兩種不同的MIME類型
    FormBody :"application/x-www-form-urlencoded"
    MultipartBody:"multipart/"+xxx.
    
  • Response類說明
    • Response抽象成響應數據
    • Response包括Headers和RequestBody,而ResponseBody是abstract的,所以他的子類也是有兩個:RealResponseBody和CacheResponseBody,分別代表真實響應和緩存響應。
  • 關於Headers說明,頭部信息不是隨便寫的
    • OKHttp的封裝類Request和Response爲了應用程序編程方便,會把一些常用的Header信息專門提取出來,作爲局部變量。比如contentType,contentLength,code,message,cacheControl,tag…它們其實都是以name-value對的形勢,存儲在網絡請求的頭部信息中。

04.Call接口類說明

  • Get或者Post請求,顯示用builder構建了Request對象,然後執行了OKHttpClient.java的newCall方法,那麼咱們就看看這個newCall裏面都做什麼操作?
    //準備將來某個時候執行的{@code請求}。
    @Override 
    public Call newCall(Request request) {
        return RealCall.newRealCall(this, request, false /* for web socket */);
    }
    
  • Call類詳解
    • 有道詞典翻譯該類註釋:調用是準備執行的請求。call可以取消。由於此對象表示單個請求/響應對(流),因此不能執行兩次。
  • 主要是HTTP請求任務封裝
    • 可以說我們能用到的操縱基本上都定義在這個接口裏面了,所以也可以說這個類是OKHttp類的核心類了。我們可以通過Call對象來操作請求,同步請求execute,異步請求enqueue,這兩個想必都是很熟悉呢。而Call接口內部提供了Factory工廠方法模式(將對象的創建延遲到工廠類的子類去進行,從而實現動態配置)。
    • Call接口提供了內部接口Factory(用於將對象的創建延遲到該工廠類的子類中進行,從而實現動態的配置)。
  • Call類接口
    • 繼承Cloneable類,表明是可以clone的。接口中幾個方法用的都非常多……
    public interface Call extends Cloneable {
    
      Request request();
      
      Response execute() throws IOException;
    
      void enqueue(Callback responseCallback);
    
      void cancel();
    
      boolean isExecuted();
    
      boolean isCanceled();
    
      Call clone();
    
      interface Factory {
        Call newCall(Request request);
      }
    }
    

05.RealCall類說明

5.1 RealCall構造

  • RealCall類構造創建對象
    • 在源碼中,OKHttpClient實現了Call.Factory接口,返回了一個RealCall對象。那我們就來看下RealCall這個類。代碼如下所示:
    @Override 
    public Call newCall(Request request) {
        return RealCall.newRealCall(this, request, false /* for web socket */);
    }
    
    static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
        // Safely publish the Call instance to the EventListener.
        RealCall call = new RealCall(client, originalRequest, forWebSocket);
        call.eventListener = client.eventListenerFactory().create(call);
        return call;
    }
    
    • 1、OkHttpClient的newCall方法裏面new了RealCall的對象,但是RealCall的構造函數需要傳入一個OKHttpClient對象和Request對象(PS:第三個參數false表示不是webSokcet)。因此RealCall包裝了Request對象。所以RealCall可以很方便地使用這兩個對象。
    • 2、RealCall裏面的兩個關鍵方法是:execute 和 enqueue。分別用於同步和異步得執行網絡請求。
    • 3、RealCall還有一個重要方法是:getResponseWithInterceptorChain,添加攔截器,通過攔截器可以將一個流式工作分解爲可配置的分段流程,既增加了靈活性也實現瞭解耦,關鍵還可以自有配置,非常完美。

5.2 execute方法調用

  • client.newCall(request).execute();實際上執行的是RealCall的execute方法,現在咱們再回來看下RealCall的execute的具體實現
    • 首先是判斷call是否執行過,可以看出每個Call對象只能使用一次原則。
    @Override public Response execute() throws IOException {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        try {
          client.dispatcher().executed(this);
          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);
        }
    }
    
  • 然後接着看captureCallStackTrace方法
    • RealCall的captureCallStackTrace() 又調用了Platform.get().getStackTraceForCloseable()。
    • 其實是調用AndroidPlatform. getStackTraceForCloseable(String closer)方法。這裏就不詳細說了,後面詳細說。
    • 然後retryAndFollowUpInterceptor.setCallStackTrace(),在這個方法裏面什麼都沒做就是set一個object進去。
    • 綜上所示captureCallStackTrace()這個方法其實是捕獲了這個請求的StackTrace。
    private void captureCallStackTrace() {
        Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
        retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
    }
    
    public Object getStackTraceForCloseable(String closer) {
        if (logger.isLoggable(Level.FINE)) {
          return new Throwable(closer); // These are expensive to allocate.
        }
        return null;
    }
    

5.3 enqueue異步方法

  • client.newCall(request).enqueue();實際上執行的是RealCall的enqueue方法,現在咱們再回來看下RealCall的enqueue的具體實現。
    @Override public void enqueue(Callback responseCallback) {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
    }
    
  • 由於executed默認爲false,所以先進行判斷是否爲true,爲true則直接跑異常,沒有則設置爲true,可以看出executed這個是一個標誌,標誌這個請求是否已經正在請求中,合同步一樣先調用了captureCallStackTrace();然後調用 client.dispatcher().enqueue(new AsyncCall(responseCallback));client.dispatcher()返回的是Dispatcher對象所以實際調用的是Dispatcher的enqueue()

06.Dispatcher類說明

6.1 execute同步方法源碼分析

  • 然後看一下關鍵性代碼,如下所示。
    • 進入了第一個核心類—Dispatcher的的execute方法。
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
        //最後需要調用finished方法結束
      client.dispatcher().finished(this);
    }
    
  • 看下OKHttpClient的dispatcher()方法的具體內容
    • 發現client.dispatcher()返回的是Dispatcher對象,那麼這個Dispatcher對象是何時創建的呢?
    public Dispatcher dispatcher() {
        return dispatcher;
    }
    
  • 在OkHttpClient.java裏面Build類裏面的構造函數裏面
    • 默認執行Builder()放到時候就創建了一個Dispatcher
    //OkHttpClient.java
    public static final class Builder {
        public Builder() {
          dispatcher = new Dispatcher();
        }
    }
    
  • 接着看看Dispatcher類中executed執行方法
    • 裏面發現是runningSyncCalls執行了add方法,可以發現runningSyncCalls是ArrayDeque對象。
    synchronized void executed(RealCall call) {
        runningSyncCalls.add(call);
    }
    
  • 查看dispatcher裏面怎麼定義runningSyncCalls的
    • 原來runningSyncCalls是雙向隊列啊,突然發現Dispatcher裏面定義了三個雙向隊列,看下注釋,我們大概能明白readyAsyncCalls 是一個存放了等待執行任務Call的雙向隊列,runningAsyncCalls是一個存放異步請求任務Call的雙向任務隊列,runningSyncCalls是一個存放同步請求的雙向隊列。
    /** 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<>();
    
  • 接着看一下getResponseWithInterceptorChain源代碼
    • 發現 new了一個ArrayList,然後就是不斷的add,後面 new了 RealInterceptorChain對象,最後調用了chain.proceed()方法。
    Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List<Interceptor> interceptors = new ArrayList<>();
        //添加開發者應用層自定義的Interceptor
        interceptors.addAll(client.interceptors());
        //這個Interceptor是處理請求失敗的重試,重定向    
        interceptors.add(retryAndFollowUpInterceptor);
        //這個Interceptor工作是添加一些請求的頭部或其他信息
        //並對返回的Response做一些友好的處理(有一些信息你可能並不需要)
        interceptors.add(new BridgeInterceptor(client.cookieJar()));
        //這個Interceptor的職責是判斷緩存是否存在,讀取緩存,更新緩存等等
        interceptors.add(new CacheInterceptor(client.internalCache()));
        //這個Interceptor的職責是建立客戶端和服務器的連接
        interceptors.add(new ConnectInterceptor(client));
        if (!forWebSocket) {
          //添加開發者自定義的網絡層攔截器
          interceptors.addAll(client.networkInterceptors());
        }
        interceptors.add(new CallServerInterceptor(forWebSocket));
        //一個包裹這request的chain
        Interceptor.Chain chain = new RealInterceptorChain(
            interceptors, null, null, null, 0, originalRequest);
        //把chain傳遞到第一個Interceptor手中
        return chain.proceed(originalRequest);
    }
    
    • 看下RealInterceptorChain的構造函數。可以發現這裏面僅僅只是一些賦值操作。
    public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
          HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
          EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
        this.interceptors = interceptors;
        this.connection = connection;
        this.streamAllocation = streamAllocation;
        this.httpCodec = httpCodec;
        this.index = index;
        this.request = request;
        this.call = call;
        this.eventListener = eventListener;
        this.connectTimeout = connectTimeout;
        this.readTimeout = readTimeout;
        this.writeTimeout = writeTimeout;
    }
    
    • 跟蹤下chain.proceed()方法,看看做了什麼。
    public interface Interceptor {
      Response intercept(Chain chain) throws IOException;
    
      interface Chain {
        Request request();
    
        Response proceed(Request request) throws IOException;
    
        @Nullable Connection connection();
    
        Call call();
      }
    }
    
    • 由於Interceptor是個接口,所以應該是具體實現類RealInterceptorChain的proceed實現。
    public final class RealInterceptorChain implements Interceptor.Chain {
    
      @Override public Response proceed(Request request) throws IOException {
        return proceed(request, streamAllocation, httpCodec, connection);
      }
    
      public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
          RealConnection connection) throws IOException {
        if (index >= interceptors.size()) throw new AssertionError();
    
        calls++;
    
        // If we already have a stream, confirm that the incoming request will use it.
        if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
              + " must retain the same host and port");
        }
    
        // If we already have a stream, confirm that this is the only call to chain.proceed().
        if (this.httpCodec != null && calls > 1) {
          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
              + " must call proceed() exactly once");
        }
    
        // Call the next interceptor in the chain.
        RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
            connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
            writeTimeout);
        Interceptor interceptor = interceptors.get(index);
        Response response = interceptor.intercept(next);
    
        // Confirm that the next interceptor made its required call to chain.proceed().
        if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
          throw new IllegalStateException("network interceptor " + interceptor
              + " must call proceed() exactly once");
        }
    
        // Confirm that the intercepted response isn't null.
        if (response == null) {
          throw new NullPointerException("interceptor " + interceptor + " returned null");
        }
    
        if (response.body() == null) {
          throw new IllegalStateException(
              "interceptor " + interceptor + " returned a response with no body");
        }
    
        return response;
      }
    }
    
    • 看到在proceed方面裏面又new了一個RealInterceptorChain類的next對象,溫馨提示下,裏面的streamAllocation, httpCodec, connection都是null,所以這個next對象和chain最大的區別就是index屬性值不同chain是0.而next是1,然後取interceptors下標爲1的對象的interceptor。由從上文可知,如果沒有開發者自定義的Interceptor時,首先調用的RetryAndFollowUpInterceptor,如果有開發者自己定義的interceptor則調用開發者interceptor。

6.2 enqueue異步方法

  • 先看call類中的代碼
    • client.dispatcher()返回的是Dispatcher對象所以實際調用的是Dispatcher的enqueue()。
    @Override public void enqueue(Callback responseCallback) {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
    }
    
  • 接着重點看一下client.dispatcher().enqueue方法操作了什麼
    • 根據源碼和註釋大家可以看到如果正在執行的異步請求小於64,並且請求同一個主機小於5的時候就先往正在運行的隊列裏面添加這個call,然後用線程池去執行這個call,否則就把他放到等待隊列裏面。執行這個call的時候,自然會去走到這個call的run方法。
    private int maxRequests = 64;
    private int maxRequestsPerHost = 5;
    
    synchronized void enqueue(AsyncCall call) {
      //如果正在執行的請求小於設定值即64,並且請求同一個主機的request小於設定值即5
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
          //添加到執行隊列,開始執行請求
          runningAsyncCalls.add(call);
          //獲得當前線程池,沒有則創建一個
          executorService().execute(call);
        } else {
          //添加到等待隊列中
          readyAsyncCalls.add(call);
        }
    }
    
  • 那麼咱們看下AsyncCall.java這個類,而AsyncCall.java又繼承自NamedRunnable.java咱們就一起看下他們的源碼
    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();
    }
    
    final class AsyncCall extends NamedRunnable {
        private final Callback responseCallback;
    
        AsyncCall(Callback responseCallback) {
          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 {
            client.dispatcher().finished(this);
          }
        }
    }
    
    • 上面看到NamedRunnable的構造方法設置了name在的run方法裏面設定爲當前線程的name,而NamedRunnable的run方法裏面調用了它自己的抽象方法execute,由此可見NamedRunnable的作用就是設置了線程的name,然後回調子類的execute方法,那麼我們來看下AsyncCall的execute方法。貌似好像又回到了之前同步的getResponseWithInterceptorChain()裏面,根據返回的response來這隻callback回調。

07.主要流程圖

  • 根據上面分析,大概流程圖如下所示
    • image
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章