OkHttp源碼分析

異步請求流程

  • 從這樣一句話開始發出一個異步的請求

okHttpClient.newCall(request).enqueue(callback);緩存

  • 實際上調用的是 RealCall 的 enqueue 方法,將回調包裝成一個 AsyncCall(NamedRunnabled的子類) 傳遞給了 Client 的 Dispatcher
//@see OkHttpClient
  @Override public Call newCall(Request request) {
    return new RealCall(this, request);
  }
  
  //@see RealCall
  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }
  • 每當 Dispatcher 收到一個新的 AsyncCall
    1. 若是有空閒的線程就去將其放入執行隊列,並執行它
    2. 沒有的話,就放入等待隊列
//@see Dispatcher
  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }
  • AsyncCall 的執行過程經過 getResponseWithInterceptorChain() 來鏈式調用client.interceptors(),從上到下層層包裝了各類緩存、重試等機制,並添加部分默認的Headers參數等,最後調用到CallServerInterceptor.intercept(Chain chain)方法和服務器創建 Socket 鏈接取得 Response,而後再把 Response 沿着來時的順序由下往上層層返回,並進行相應的處理,最後返回到 AsyncCall 的 execute 方法中。服務器

  • 而後相應的調用成功或失敗的回調(仍是在執行線程中,不會切換到主線程)cookie

//@see RealCall.AsyncCall
    @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);
      }
    }
  
  private 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(
        retryAndFollowUpInterceptor.isForWebSocket()));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }
  • 最後在client.dispatcher().finished()方法中會
    1. 將該 AsyncCall 從執行隊列中移除
    2. 調用Dispatcher.promoteCalls()方法來將等待隊列中的 AsyncCall 放入執行隊列中並執行
//@see Dispatcher
  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.
    }
  }

同步請求流程

這個會把 realCall 放到 dispatcher 的 runningSyncCalls 中,用於對請求的統一管理異步

並直接在當前線程調用getResponseWithInterceptorChain()得到 Responseide

//@see RealCall
  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }
相關文章
相關標籤/搜索