OkHttp3 -- 源碼

以get請(qǐng)求為例子:

  OkHttpClient client=new OkHttpClient();
  Request request=new Request.Builder().url("").build();
  Response response=client.newCall(request).execute();

三行代碼就可以創(chuàng)建一個(gè)請(qǐng)求 , 接下來我們查看具體的代碼

OkHttpClient client=new OkHttpClient();

public OkHttpClient() {
    this(new Builder());
  }

構(gòu)造方法中再次調(diào)用有參的構(gòu)造方法 , 點(diǎn)進(jìn)去之后 , 會(huì)發(fā)現(xiàn)一系列的初始化操作 . 其中我們關(guān)心這幾個(gè)屬性 , 先記住名字就好

  • dispatcher 分發(fā)器
  • interceptors 應(yīng)用層的攔截器
  • networkInterceptors 網(wǎng)絡(luò)層攔截器

Request request=new Request.Builder().url("").build();

其實(shí)這里就是一個(gè)對(duì)象的初始化過程.......不多解釋了

Response response=client.newCall(request).execute();

從newCall()方法開始:

@Override public Call newCall(Request request) {
    return new RealCall(this, request);
  }

直接實(shí)例化了另一個(gè)類RealCall, 實(shí)例化之后 , 回到原來的語句中 , 接下來執(zhí)行的execute()方法 , 就肯定是在該類中進(jìn)行的了
這里不要直接點(diǎn)擊execute , 會(huì)跑偏的= =

@Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    try {
      // 使用分發(fā)器來處理
      client.dispatcher().executed(this);
      // 交由攔截器來處理
      Response result = getResponseWithInterceptorChain(false);
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }

這里主要有兩個(gè)方法 , 一個(gè)分發(fā) , 一個(gè)攔截. 我們先看分發(fā)器的executed的實(shí)現(xiàn):

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

恩.......比較簡(jiǎn)單昂 , 就是將請(qǐng)求添加到隊(duì)列中 , 這里用到隊(duì)列數(shù)據(jù)結(jié)構(gòu). 加入隊(duì)列之后, 攔截器來進(jìn)一步處理

private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
    return chain.proceed(originalRequest);
  }

首先創(chuàng)建了一個(gè)應(yīng)用層的攔截器ApplicationInterceptorChain , 再調(diào)用攔截器的proceed方法 , 獲取到請(qǐng)求數(shù)據(jù).
先點(diǎn)開ApplicationInterceptorChain , 發(fā)現(xiàn)它是一個(gè)內(nèi)部類 , 初始化了一些東西 , 然后接下來的proceed方法也應(yīng)該在這個(gè)類里面了

@Override public Response proceed(Request request) throws IOException {
      // If there's another interceptor in the chain, call that.
      if (index < client.interceptors().size()) {
        Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
        Interceptor interceptor = client.interceptors().get(index);
        Response interceptedResponse = interceptor.intercept(chain);

        if (interceptedResponse == null) {
          throw new NullPointerException("application interceptor " + interceptor
              + " returned null");
        }

        return interceptedResponse;
      }

      // No more interceptors. Do HTTP.
      // 開始請(qǐng)求
      return getResponse(request, forWebSocket);
    }
  }

這里先判斷了當(dāng)前攔截器有沒有對(duì)應(yīng)的處理 , 沒有就新建一個(gè)攔截器 , 并執(zhí)行intercept方法 . 攔截器可以用來轉(zhuǎn)換格式 , 重寫請(qǐng)求等......最后 , 反回了真正的請(qǐng)求getResponse()

  Response getResponse(Request request, boolean forWebSocket) throws IOException {
    // Copy body metadata to the appropriate request headers.
    RequestBody body = request.body();

    // 拼接請(qǐng)求頭
    if (body != null) {
      Request.Builder requestBuilder = request.newBuilder();

      MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

      long contentLength = body.contentLength();
      if (contentLength != -1) {
        requestBuilder.header("Content-Length", Long.toString(contentLength));
        requestBuilder.removeHeader("Transfer-Encoding");
      } else {
        requestBuilder.header("Transfer-Encoding", "chunked");
        requestBuilder.removeHeader("Content-Length");
      }

      request = requestBuilder.build();
    }

    // Create the initial HTTP engine. Retries and redirects need new engine for each attempt.
    // 創(chuàng)建HTTP engine, 用于發(fā)送和回復(fù)的細(xì)節(jié)處理
    engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);

    int followUpCount = 0;
    while (true) {
      if (canceled) {
        engine.releaseStreamAllocation();
        throw new IOException("Canceled");
      }

      boolean releaseConnection = true;
      try {
        // 發(fā)送請(qǐng)求
        engine.sendRequest();

        // 讀取回復(fù)
        engine.readResponse();
        releaseConnection = false;
      } catch (RequestException e) {
        // The attempt to interpret the request failed. Give up.
        throw e.getCause();
      } catch (RouteException e) {
        // The attempt to connect via a route failed. The request will not have been sent.
        HttpEngine retryEngine = engine.recover(e.getLastConnectException(), true, null);
        if (retryEngine != null) {
          releaseConnection = false;
          engine = retryEngine;
          continue;
        }
        // Give up; recovery is not possible.
        throw e.getLastConnectException();
      } catch (IOException e) {
        // An attempt to communicate with a server failed. The request may have been sent.
        HttpEngine retryEngine = engine.recover(e, false, null);
        if (retryEngine != null) {
          releaseConnection = false;
          engine = retryEngine;
          continue;
        }

        // Give up; recovery is not possible.
        throw e;
      } finally {
        // We're throwing an unchecked exception. Release any resources.
        if (releaseConnection) {
          StreamAllocation streamAllocation = engine.close();
          streamAllocation.release();
        }
      }

      Response response = engine.getResponse();
      Request followUp = engine.followUpRequest();

      if (followUp == null) {
        if (!forWebSocket) {
          engine.releaseStreamAllocation();
        }
        return response;
      }

      StreamAllocation streamAllocation = engine.close();

      if (++followUpCount > MAX_FOLLOW_UPS) {
        streamAllocation.release();
        throw new ProtocolException("Too many follow-up requests: " + followUpCount);
      }

      if (!engine.sameConnection(followUp.url())) {
        streamAllocation.release();
        streamAllocation = null;
      } else if (streamAllocation.stream() != null) {
        throw new IllegalStateException("Closing the body of " + response
            + " didn't close its backing stream. Bad interceptor?");
      }

      request = followUp;
      engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null,
          response);
    }
  }

首先 , 設(shè)置請(qǐng)求頭 , 拼接一條完整的請(qǐng)求, 然后初始化HttpEngine用于細(xì)節(jié)優(yōu)化 , 再開始請(qǐng)求 , 請(qǐng)求完成后讀取請(qǐng)求結(jié)果.

  1. 開始請(qǐng)求部分:
 public void sendRequest() throws RequestException, RouteException, IOException {
    if (cacheStrategy != null) return; // Already sent.
    if (httpStream != null) throw new IllegalStateException();
    // 首先 ,對(duì)請(qǐng)求頭再次做一次處理
    Request request = networkRequest(userRequest);
    // 獲取用戶設(shè)置的緩存
    InternalCache responseCache = Internal.instance.internalCache(client);
    // 從緩存中獲取之前請(qǐng)求過的Response
    Response cacheCandidate = responseCache != null
        ? responseCache.get(request)
        : null;

    long now = System.currentTimeMillis();
     // 根據(jù)請(qǐng)求和緩存結(jié)果來設(shè)置緩存策略,先從緩存拿,如果超時(shí),那么從網(wǎng)絡(luò)請(qǐng)求.
    cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();
    networkRequest = cacheStrategy.networkRequest;
    cacheResponse = cacheStrategy.cacheResponse;

    if (responseCache != null) {
      responseCache.trackResponse(cacheStrategy);
    }

    if (cacheCandidate != null && cacheResponse == null) {
      closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
    }
...
...
try {
      // 建立鏈接, 使用socket創(chuàng)建,可以自動(dòng)選擇偏好鏈接, 選擇連接時(shí),首先從連接池來查找,
      // 沒有的話使用路徑選擇器,若還找不到的話就新建一個(gè)連接,同時(shí)將連接放到連接池中
      httpStream = connect();
      httpStream.setHttpEngine(this);

      if (writeRequestHeadersEagerly()) {
        long contentLength = OkHeaders.contentLength(request);
        if (bufferRequestBody) {
          if (contentLength > Integer.MAX_VALUE) {
            throw new IllegalStateException("Use setFixedLengthStreamingMode() or "
                + "setChunkedStreamingMode() for requests larger than 2 GiB.");
          }

          if (contentLength != -1) {
            // Buffer a request body of a known length.
            httpStream.writeRequestHeaders(networkRequest);
            requestBodyOut = new RetryableSink((int) contentLength);
          } else {
            // Buffer a request body of an unknown length. Don't write request headers until the
            // entire body is ready; otherwise we can't set the Content-Length header correctly.
            requestBodyOut = new RetryableSink();
          }
        } else {
          httpStream.writeRequestHeaders(networkRequest);
          requestBodyOut = httpStream.createRequestBody(networkRequest, contentLength);
        }
      }
      success = true;
    } finally {
      // If we're crashing on I/O or otherwise, don't leak the cache body.
      if (!success && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • OKHttp牛逼之處 1.支持HTTP2/SPDY黑科技 --->okHttp中分包就分為Http1 和Http2...
    河里的枇杷樹閱讀 280評(píng)論 0 0
  • 參考資源 官網(wǎng) 國(guó)內(nèi)博客 GitHub官網(wǎng) 鑒于一些關(guān)于OKHttp3源碼的解析文檔過于碎片化,本文系統(tǒng)的,由淺入...
    風(fēng)骨依存閱讀 12,707評(píng)論 11 82
  • 最近抽時(shí)間分析一下 OKHttp3 的源碼,關(guān)于 OKHttp 源碼解析的資料已經(jīng)有很多了,但是關(guān)于 OKHttp...
    lijiankun24閱讀 399評(píng)論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評(píng)論 19 139
  • 在上一篇文章中,主要梳理了 OKHttp 請(qǐng)求的整體流程,了解到攔截器在其中有非常重要的意義,那么本篇文章就重點(diǎn)介...
    lijiankun24閱讀 926評(píng)論 0 3

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