OKHttp 源碼分析

基本使用

  1. 異步GET

     Request.Builder builder = new Request.Builder().url("https://www.baidu.com/");
     builder.method("GET",null);
     Request build = builder.build();
     OkHttpClient client = new OkHttpClient();
     Call call = client.newCall(build);
     call.enqueue(new Callback() {
         @Override
         public void onFailure(Call call, IOException e) {
    
         }
    
         @Override
         public void onResponse(Call call, Response response) throws IOException {
             System.out.println(response.body().string());
         }
     }); 
    
  2. 異步POST

     FormBody.Builder builder = new FormBody.Builder().add("XXX", "XXX");
     FormBody build = builder.build();
     Request request = new Request.Builder().url("https://.........").post(build).build();
     OkHttpClient client = new OkHttpClient();
     Call call = client.newCall(request);
     call.enqueue(new Callback() {
         @Override
         public void onFailure(Call call, IOException e) {
    
         }
    
         @Override
         public void onResponse(Call call, Response response) throws IOException {
             System.out.println(response.body().string());
         }
     });
    

用法都非常簡單,只用簡單的調(diào)用一下,就能實現(xiàn)所想需要實現(xiàn)的GET,POST請求。

源碼分析

我們還是從請求處理開始分析起:

Call call = client.newCall(request);

我們通常就會這樣聲明一個 Call 對象 然后執(zhí)行異步 enqueue() 或者同步 execute()方法。

點進 newCall 里面:

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

這里實際就是返回了 RealCall 這個對象, 而接下來 網(wǎng)絡(luò)請求 實際上就是調(diào)用 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));
}

從上面可以得知請求是從 dispatcher 完成的。

接下來分析 dispatcher

在 Dispatcher.java 下

先看看這個類所定義的變量吧

最大并發(fā)請求數(shù)
private int maxRequests = 64;
每個主機最大的請求數(shù)
private int maxRequestsPerHost = 5;

/** Executes calls. Created lazily. */
消費者線程池
private @Nullable ExecutorService executorService;

/** 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<>();

由此可以看出他維護個各種隊列,把不同的Call放置相對應(yīng)的隊列中去,隊列中的請求最后會一個個的進行訪問。

接下來看看構(gòu)造函數(shù)

/** Executes calls. Created lazily. */
private @Nullable ExecutorService executorService;

public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}

public Dispatcher() {
}

構(gòu)造函數(shù)有兩個,一個構(gòu)造函數(shù)是帶參的,這個參數(shù)就是自己實現(xiàn)的線程池,如果我們調(diào)用不帶參的構(gòu)造函數(shù)時,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;
}

從上面看到他會創(chuàng)建一個默認的線程池 。

那么接下來在異步請求的時候會調(diào)用enqueue() 方法 ,而從下面我們可以看到 當異步請求隊列 數(shù)量小于 64 并且正在運行的請求主機數(shù)小于5時,會把請求放置在 runningAsyncCalls 中 并在線程池中執(zhí)行。 否則就加入到 readyAsyncCalls 中進行緩存。

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

然后就會執(zhí)行以下方法

executorService().execute(call);

executorService()會返回一個線程池 , 如果使用的是默認線程池的話:那么在 ThreadPoolExecutor 內(nèi) ,所要傳進去的是 Runnable 這個接口,

public void execute(Runnable command) {
    .....   
}

再看看 AsyncCall 這個類吧 :

AsyncCall 是 RealCall 的 內(nèi)部類 。 他繼承了NamedRunnable,而NamedRunnable正是實現(xiàn)了Runnable方法。

在NamedRunnable里面實現(xiàn)了run() 方法 ,run() 里面調(diào)用了他的一個 抽象方法 :

protected abstract void execute();

那么子類就只要實現(xiàn) execute 方法就可以了:

所以就回到了 AsyncCall 中實現(xiàn)的 execute() 方法

@Override protected void execute() {
  try{
  ......
  } finally {
    client.dispatcher().finished(this);
  }
}

先來看看這個方法最后都做了什么吧 :

無論如何都會調(diào)用到 client.dispatcher().finished(this); 這個方法

進去 finished 方法 ,我們看到最后調(diào)用的方法為以下:

void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
}

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      
      注 1   
      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();
    }
}

從上面可以看到 calls 是 runningAsyncCalls ,首先他先從隊列移除,然后執(zhí)行
promoteCalls() ,隨后將更新 runningCallsCount 和 idleCallback 。

主要的方法就是 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.
    }
}

從for語句可以明顯看出 因為 runningAsyncCalls 的請求被移除了 , 那么就會從 readyAsyncCalls 中拿出請求向 runningAsyncCalls 補充 。

接著我們回到 execute() 方法 ,看看其中實現(xiàn)了什么:

@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 就是請求的結(jié)果, 而網(wǎng)絡(luò)請求交給了
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);
}

構(gòu)建了一大堆攔截器,最后 創(chuàng)建了 RealInterceptorChain 這個 對象,他實際作用就是一個 攔截鏈 。

最后把請求交給了攔截鏈的proceed () 方法:

@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 {
    
    .....
    
    注 1 
    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);
    
    .....
    
    return response;
}

注 1 : 從上面可以看出了這個攔截鏈會不斷的調(diào)用下一個攔截器。從而現(xiàn)在分析一下所添加的攔截器吧。

在getResponseWithInterceptorChain() 方法中,里面就是添加了一堆攔截器

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

在拿取攔截鏈里面的攔截器,然后一一執(zhí)行。

retryAndFollowUpInterceptor -- 這攔截器主要是做重試,網(wǎng)絡(luò)錯誤,以及請求重定向的一些操作。

BridgeInterceptor -- 這個攔截器,主要把用戶的請求轉(zhuǎn)換為網(wǎng)絡(luò)的請求,負責對Request和Response報文進行加工。

CacheInterceptor -- 緩存攔截器

ConnectInterceptor -- 連接攔截器,主要是處理連接服務(wù)器,以及http , https的包裝

CallServerInterceptor -- 服務(wù)攔截器,主要是發(fā)送(write、input)、讀?。╮ead、output)數(shù)據(jù)。也是攔截器的最后一個環(huán)節(jié),這里就真正拿到了網(wǎng)絡(luò)的結(jié)果了。

攔截器會不斷的調(diào)用下一個攔截器,最后全部執(zhí)行完。在每個攔截器里面,你可以看到類似的代碼 : Response networkResponse = chain.proceed(...); 這就是調(diào)用了下一個攔截器。

攔截器所要執(zhí)行的內(nèi)容基本就如上的簡述了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容