1. 程式人生 > >原始碼解析一次OKHttp請求的過程

原始碼解析一次OKHttp請求的過程

OkHttp這個庫有多優秀作為Androider大家心裡都明白,應該說合格的開發者都認識它。那麼,這裡簡單看個OKHttp的介面請求姿勢:

OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
        .url("https://www.xxxx.com/xxx/xxx/xxx")
        .build();
Call call = okHttpClient.newCall(request);
//開始執行非同步介面請求
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
    	// 這裡介面請求失敗
    }
    @Override
    public void onResponse(Call call, Response response) throws IOException {
    	// 這裡介面請求成功
    }
});

所以很明顯了弄懂了上面幾個類的是幹嘛、上個幾個流程做了什麼自然就明白了OKHttp的執行流程了,那麼就開始分析吧。

OKHttp請求中需要的物件

Request這個類是典型的’Builder’設計模式,看一眼他的成員屬性就知道這個類是幹嘛的了。

public final class Request {
  final HttpUrl url;
  final String method;
  final Headers headers;
  final @Nullable RequestBody body;
  final Object tag;
  .
  .
  .
  }

看看變數名就知道了這個類封裝那些玩意,還是很愉快的完成了一小步。

OkHttpClient這個類類似個Manager類,裡面的成員屬性自然也比較多了。 我們重點關注Dispatcher這個執行緒池屬性:

  // 可以傳入執行緒池,從而自定義OKHttp執行緒池 
  public Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }

  public Dispatcher() {
  }
  // 初始化執行緒池 
  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;
  }

所以Dispatcher就是一個執行緒池管理類,用於分發每一次的Http請求。

Call是介面真正的實現類是RealCall,而RealCall有個內部類叫AsyncCall是個介面,最終加入Dispatcher執行緒池的就是AsyncCall物件。

執行Http請求操作

我們從okHttpClient.newCall操作開始閱讀:

  /**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
  }

所以這裡封裝了一個RealCall物件然後執行enqueue方法,我們進入該方法看看一下程式碼:

  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

再看最後一行程式碼會執行Dispatcher.enqueue方法,同樣的進入看看程式碼怎麼執行的:

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

由於AsyncCall是實現了NamedRunnable介面,所以執行緒池就會執行NamedRunnable.run方法,這樣子自然就執行到AsyncCall.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 {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

我們可以看到這裡直接通過getResponseWithInterceptorChain()方法直接得到Response然後通過Callback回撥資料回去。

攔截器Interceptor

通過上面我們知道已經得到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);
    return chain.proceed(originalRequest);
  }

我們可以看到系統已經為我們定義幾個預設的攔截器,他們的作用一起呼叫時序如下: 在這裡插入圖片描述 這裡知道了呼叫時序,那從什麼時候觸發呼叫?

Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);

我們可以看到是先封裝一個RealInterceptorChain物件,然後執行proceed方法自然就會執行每一個interceptor.intercept方法。OKHttp的所有精髓之一就是攔截器的使用…

最後,這裡我們也可以明白一點addInterceptor / addNetworkInterceptor兩者之間有何不同了,因為他們倆的呼叫時序不一樣。

更多攔截器的分析,將在未來找時間分析。