Okhttp3源碼解析(3)-Call分析(總體流程)

前言

前面咱們講了 Okhttp的基本用法 Okhttp3源碼解析(1)-OkHttpClient分析 Okhttp3源碼解析(2)-Request分析web

newCall分析

Call初始化

咱們首先看一下在哪用到了Call:緩存

final Call call = okHttpClient.newCall(request);

想起來了吧?不管是get仍是post請求 都要生成call對象,在上面咱們發現call實例須要一個okHttpClientrequest實例 ,咱們先點進Call類去看看:服務器

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);
  }
}

咱們發現Call是個接口, 並定義了一些方方法(方法含義在註釋上)。 咱們繼續看newCal()方法微信

@Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

繼續點擊newRealCall()去:websocket

private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

  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;
  }

從代碼中咱們發如今newRealCall()中初始化了RealCallRealCall中初始化了retryAndFollowUpInterceptorcookie

  • client: OkHttpClient 實例
  • originalRequest : 最初的Request
  • forWebSocket :是否支持websocket通訊
  • retryAndFollowUpInterceptor 從字面意思來講, 是重試和重定向攔截器 ,至於它有什麼做用咱們繼續往下看

同步請求分析

Response response = call.execute();

咱們點進execute()中查看:網絡

@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);
    }
  }

從上面代碼得知步驟: (1).經過 synchronized 保證線程同步,判斷是否已經執行過 ,若是是直接拋異常 (2). captureCallStackTrace(); 字面意思:捕獲調用堆棧跟蹤,咱們經過源碼發現裏面涉及到了retryAndFollowUpInterceptor (3). eventListener 回調 CallStart() (4). client.dispatcher().executed(this); 看到了dispatcher是否是很熟悉?以前在分析okhttpClient初始化的時候遇到了,咱們點擊executed()方法進去:數據結構

synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

發現把咱們傳進來的realcall放到了runningSyncCalls隊列中,從字面意思來講就是正在運行的同步的調用隊列中,爲何說是隊列呢? :異步

private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

Deque即雙端隊列。是一種具備隊列和棧的性質的數據結構。雙端隊列中的元素能夠從兩端彈出,相比list增長[]運算符重載。socket

(5).咱們回到execute()繼續往下分析,剩下的代碼咱們提取出三行代碼:

  • equesr result = getResponseWithInterceptorChain(); 生成一個Response 實例
  • eventListener.callFailed(this, e); :eventListener的callFailed回調
  • client.dispatcher().finished(this); :dispatcher實例的finished方法

不難看出,getResponseWithInterceptorChain()必定是此方法中的核心,字面意思是獲取攔截器鏈的響應,這就明白了,就是經過攔截器鏈處理後返回Response

getResponseWithInterceptorChain() 分析
Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());    //自定義
    interceptors.add(retryAndFollowUpInterceptor); //錯誤與跟蹤攔截器
    interceptors.add(new BridgeInterceptor(client.cookieJar()));   //橋攔截器
    interceptors.add(new CacheInterceptor(client.internalCache())); //緩存攔截器
    interceptors.add(new ConnectInterceptor(client));   //鏈接攔截器
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());  //網絡攔截器
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));  //調用服務器攔截器

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());   

    return chain.proceed(originalRequest);
  }

從上面代碼不難看出, 對最初的request作了層層攔截,每一個攔截器的原理咱們放在之後的章節去講, 這裏就不展開了!
這裏須要強調的一下 interceptors.addAll(client.interceptors()); client.interceptors() 是咱們自定義的攔截器 它是在哪定義的?如何添加?咱們去OkHttpClient類中發現: 能夠經過初始化okHttpClient實例 .addInterceptor的形式 添加。

異步請求分析

call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d("okhttp_error",e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Gson gson=new Gson();

                Log.d("okhttp_success",response.body().string());
            }
   });

點擊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));
  }

(1).經過 synchronized 保證線程同步,判斷是否已經執行過 ,若是是直接拋異常 (2). captureCallStackTrace(); 字面意思:捕獲調用堆棧跟蹤,咱們經過源碼發現裏面涉及到了retryAndFollowUpInterceptor (3). eventListener 回調 CallStart() (4). client.dispatcher().enqueue(new AsyncCall(responseCallback)); 調用了Dispatcher.enqueue()並傳入了一個**new AsyncCall(responseCallback)實例,點擊AsyncCall**查看: AsyncCall 是RealCall的內部類!

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 {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

AsyncCall繼承了NamedRunnable ,咱們看下NamedRunnable是什麼:

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();
}

原來NamedRunnable 實現了Runnable 接口 是個線程類,在run()中 添加了抽象的execute();方法,看到這裏 咱們應該有一個反應,那就是AsyncCall中具體的execute()應該在子線程執行
咱們繼續分析,client.dispatcher().enqueue(new AsyncCall(responseCallback)); 點擊進入enqueue():

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }
  • runningAsyncCalls 正在運行的異步請求的隊列
  • maxRequests 最大的請求數 64
  • maxRequestsPerHost host最大請求數 5 (能夠經過Get與Set方式自定義設置)

若是正在運行的異步請求的隊列大小低於64而且 正在請求的host數量低於5,就會執行(知足條件)

runningAsyncCalls.add(call);
     executorService().execute(call);

這裏把 AsyncCall 實例添加到 runningAsyncCalls 中。 ExecutorService 表示線程池 繼續看 executorService()

public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

其實就是生成了executorService 實例,這就明白了,AsyncCall 實例放入線程池中執行了!

若是不知足上面的請求數等條件:

readyAsyncCalls.add(call);

就會被添加到一個等待就緒的異步請求隊列中,目的是什麼呢??? 固然是等待時機再次添加到runningAsyncCalls中並放入線程池中執行,這塊邏輯在 AsyncCall 類中的 execute() 至於緣由咱們繼續往下看!

剛纔咱們說了,若是條件知足, AsyncCall 實例就會在線程池中執行(.start),那咱們直接去看run()中的 execute()

@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 {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }

上面代碼中得知, 首先經過層層攔截器鏈處理生成了response;而後經過一系列的判斷,responseCallback進行onResponseonFailure回調,最後調用的Dispatcher.finifshed() 這裏須要注意的是 這裏的Dispatcher.finifshed(this)與同步中的Dispatcher.finifshed(this)不同 參數不一樣。

/** Used by {@code AsyncCall#run} to signal completion. */
  void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }

咱們繼續看具體的finifshed()方法:

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!");
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }

在線程同步的狀況下 執行了promoteCalls();

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);
      }

      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }

通過一系列的判斷, 對等待就緒的異步隊列進行遍歷,生成對應的AsyncCall 實例,並添加到runningAsyncCalls中,最後放入到線程池中執行! 這裏就是咱們上面說到的等待就緒的異步隊列如何與runningAsyncCalls對接的邏輯。

總結

同步請求流程:
  • 生成call實例realcall
  • Dispatcher.executed()中的runningSyncCalls 添加realcall到此隊列中
  • 經過 getResponseWithInterceptorChain() 對request層層攔截,生成Response
  • 經過Dispatcher.finished(),把call實例從隊列中移除,返回最終的response
異步請求流程:
  • 生成一個AsyncCall(responseCallback)實例(實現了Runnable)
  • AsyncCall實例放入了Dispatcher.enqueue()中,並判斷maxRequests (最大請求數)maxRequestsPerHost(最大host請求數)是否知足條件,若是知足就把AsyncCall添加到runningAsyncCalls中,並放入線程池中執行;若是條件不知足,就添加到等待就緒的異步隊列,當那些知足的條件的執行時 ,在Dispatcher.finifshed(this)中的promoteCalls();方法中 對等待就緒的異步隊列進行遍歷,生成對應的AsyncCall 實例,並添加到runningAsyncCalls中,最後放入到線程池中執行,一直到全部請求都結束。

至此OKhttp總體流程就分析完了, 下一篇會分塊去分析,但願對你們有所幫助...

你們能夠關注個人微信公衆號:「秦子帥」一個有質量、有態度的公衆號!

公衆號

相關文章
相關標籤/搜索