OkHttp3 源碼解讀

同步GET請(qǐng)求過(guò)程

//HTTP GET
    public String get(String url) throws IOException {
        //新建OKHttpClient客戶端
        OkHttpClient client = new OkHttpClient();
        //新建一個(gè)Request對(duì)象
        Request request = new Request.Builder()
                .url(url)
                .build();
        //Response為OKHttp中的響應(yīng)
        Response response = client.newCall(request).execute();
        if (response.isSuccessful()) {
            return response.body().string();
        }else{
            throw new IOException("Unexpected code " + response);
        }
    }

第一步 OkHttpClient

OkHttpClient client = new OkHttpClient();

直接上代碼

public OkHttpClient() {
    this(new Builder());
  }
public Builder() {
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      proxySelector = ProxySelector.getDefault();
      cookieJar = CookieJar.NO_COOKIES;
      socketFactory = SocketFactory.getDefault();
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      certificatePinner = CertificatePinner.DEFAULT;
      proxyAuthenticator = Authenticator.NONE;
      authenticator = Authenticator.NONE;
      connectionPool = new ConnectionPool();
      dns = Dns.SYSTEM;
      followSslRedirects = true;
      followRedirects = true;
      retryOnConnectionFailure = true;
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
      pingInterval = 0;
    }
Dispatcher dispatcher;  //分發(fā)器
    @Nullable Proxy proxy;  //代理
    List<Protocol> protocols;  //協(xié)議
    List<ConnectionSpec> connectionSpecs;  //傳輸層版本和連接協(xié)議
    final List<Interceptor> interceptors = new ArrayList<>();  //攔截器
    final List<Interceptor> networkInterceptors = new ArrayList<>();  //網(wǎng)絡(luò)攔截器
    EventListener.Factory eventListenerFactory;
    ProxySelector proxySelector; //代理選擇
    CookieJar cookieJar;   //cookie
    @Nullable Cache cache;  //緩存
    @Nullable InternalCache internalCache; //內(nèi)部緩存
    SocketFactory socketFactory; //socket 工廠
    @Nullable SSLSocketFactory sslSocketFactory; //安全套接層socket 工廠,用于HTTPS
    @Nullable CertificateChainCleaner certificateChainCleaner; // 驗(yàn)證確認(rèn)響應(yīng)證書(shū) 適用 HTTPS 請(qǐng)求連接的主機(jī)名少辣。
    HostnameVerifier hostnameVerifier; //  主機(jī)名字確認(rèn)
    CertificatePinner certificatePinner; //  證書(shū)鏈
    Authenticator proxyAuthenticator;  //代理身份驗(yàn)證
    Authenticator authenticator;   // 本地身份驗(yàn)證
    ConnectionPool connectionPool;  //連接池,復(fù)用連接
    Dns dns;  //域名
    boolean followSslRedirects;  //安全套接層重定向
    boolean followRedirects;  //本地重定向
    boolean retryOnConnectionFailure;  //重試連接失敗
    int connectTimeout;   //連接超時(shí)
    int readTimeout;  //read 超時(shí)
    int writeTimeout;  //write 超時(shí)
    int pingInterval;

new OkHttpClient() 主要實(shí)例化Builder 尊沸,做的就是初始化一些參數(shù)豆瘫。

第二步:創(chuàng)建 Request 對(duì)象

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

目前流行的Build模式诱桂,基本上開(kāi)源框架都能看到继谚。

Builder(Request request) {
      this.url = request.url;
      this.method = request.method;
      this.body = request.body;
      this.tag = request.tag;
      this.headers = request.headers.newBuilder();
    }

主要還是初始化請(qǐng)求需要的參數(shù)允乐,如headers费彼、url等。

第三步: Response 對(duì)象

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

真正的執(zhí)行 client.newCall().

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

真正執(zhí)行的是 RealCall.newRealCall()

  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;
  }
  1. client: 我們當(dāng)前的OkHttpClient痰娱。
  2. originalRequest :上面構(gòu)造的Request 對(duì)象弃榨。
  3. forWebSocket; 是否切換協(xié)議菩收,當(dāng)response回復(fù)101時(shí),會(huì)用到鲸睛。

接下來(lái)看下execute() 這是一個(gè)同步方法娜饵,還有一個(gè)異步的執(zhí)行方法enqueue()

@Override
  public Response execute() throws IOException {

    synchronized (this) {

      //  1
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //2
    captureCallStackTrace();

    //3
    eventListener.callStart(this);
    try {
      // 4
      client.dispatcher().executed(this);

      //5.
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
        // 6
      client.dispatcher().finished(this);
    }
  }
  1. 是否執(zhí)行過(guò),一個(gè)Call只能執(zhí)行一次.
  2. 創(chuàng)建一個(gè)跟蹤堆棧
  3. 開(kāi)始處理官辈,事件標(biāo)記
  4. 分發(fā)器箱舞,文檔里說(shuō)是異步請(qǐng)求的一個(gè)執(zhí)行策略,但是這里是同步钧萍,這里只是用來(lái)標(biāo)識(shí)一下.開(kāi)始執(zhí)行.
  5. 重點(diǎn)返回Response 對(duì)象
  6. 事件標(biāo)記結(jié)束.

重點(diǎn)看getResponseWithInterceptorChain()

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    //所有的攔截器.
    List<Interceptor> interceptors = new ArrayList<>();
    // 1
    interceptors.addAll(client.interceptors());
    //2
    interceptors.add(retryAndFollowUpInterceptor);
    //3
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //4
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //5
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      //6
      interceptors.addAll(client.networkInterceptors());
    }

    //7
    interceptors.add(new CallServerInterceptor(forWebSocket));
    // 8
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }
  1. client 自帶的一些自定義攔截器.
  2. 負(fù)責(zé)失敗重試以及重定向的攔截器
  3. 負(fù)責(zé)把用戶構(gòu)造的請(qǐng)求轉(zhuǎn)換為發(fā)送到服務(wù)器的請(qǐng)求褐缠、把服務(wù)器返回的響應(yīng)轉(zhuǎn)換為用戶友好的響應(yīng)的攔截器
  4. 請(qǐng)求從緩存中讀取和通過(guò) responses寫(xiě)入緩存的攔截器
  5. 打開(kāi)一個(gè)到目標(biāo)服務(wù)器的連接,并繼續(xù)下一個(gè)攔截器
  6. 添加client 的網(wǎng)絡(luò)攔截器
  7. 最后一個(gè)攔截器政鼠,調(diào)用服務(wù)
  8. 創(chuàng)建RealInterceptorChain 并執(zhí)行proceed

RealInterceptorChain中的proceed():

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    if (this.httpCodec != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
    //1
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);

    //2
    Interceptor interceptor = interceptors.get(index);
    //3
    Response response = interceptor.intercept(next);

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    if (response.body() == null) {
      throw new IllegalStateException(
          "interceptor " + interceptor + " returned a response with no body");
    }

    return response;
  }
  1. 在chain 中調(diào)用下一個(gè)攔截器.
  2. 獲取下一個(gè)攔截器,在除了Clien之外的第一個(gè)攔截器就是RetryAndFollowUpInterceptor
  3. 執(zhí)行攔截器
RetryAndFollowUpInterceptor
@Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request(); // 獲取Request
    RealInterceptorChain realChain = (RealInterceptorChain) chain;  //獲取Chain
    Call call = realChain.call();  // 獲取Call對(duì)象
    EventListener eventListener = realChain.eventListener();  // 獲取事件集合

    streamAllocation = new StreamAllocation(client.connectionPool(), createAddress(request.url()),
        call, eventListener, callStackTrace);

    int followUpCount = 0;
    Response priorResponse = null;
    while (true) {
      //當(dāng)連接被取消時(shí)釋放連接
      if (canceled) {
        streamAllocation.release();
        throw new IOException("Canceled");
      }

      Response response;
      boolean releaseConnection = true;
      try {
        //1
        response = realChain.proceed(request, streamAllocation, null, null);
        releaseConnection = false;
      } catch (RouteException e) {
        // The attempt to connect via a route failed. The request will not have been sent.
        if (!recover(e.getLastConnectException(), false, request)) {
          throw e.getLastConnectException();
        }
        releaseConnection = false;
        continue;
      } catch (IOException e) {
        // An attempt to communicate with a server failed. The request may have been sent.
        boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
        if (!recover(e, requestSendStarted, request)) throw e;
        releaseConnection = false;
        continue;
      } finally {
        // We're throwing an unchecked exception. Release any resources.
        if (releaseConnection) {
          streamAllocation.streamFailed(null);
          streamAllocation.release();
        }
      }

      // Attach the prior response if it exists. Such responses never have a body.
      // 2
      if (priorResponse != null) {
        response = response.newBuilder()
            .priorResponse(priorResponse.newBuilder()
                    .body(null)
                    .build())
            .build();
      }

     //3
      Request followUp = followUpRequest(response);

      if (followUp == null) {
        if (!forWebSocket) {
          streamAllocation.release();
        }
        return response;
      }

      closeQuietly(response.body());

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

      if (followUp.body() instanceof UnrepeatableRequestBody) {
        streamAllocation.release();
        throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
      }

      if (!sameConnection(response, followUp.url())) {
        streamAllocation.release();
        streamAllocation = new StreamAllocation(client.connectionPool(),
            createAddress(followUp.url()), call, eventListener, callStackTrace);
      } else if (streamAllocation.codec() != null) {
        throw new IllegalStateException("Closing the body of " + response
            + " didn't close its backing stream. Bad interceptor?");
      }

      request = followUp;
      priorResponse = response;
    }
  }

這個(gè)方法有點(diǎn)長(zhǎng)风瘦,但是重點(diǎn)是在response = realChain.proceed(request, streamAllocation, null, null);

  1. 執(zhí)行 proceed,這里便是執(zhí)行下一個(gè)攔截器,即BridgeInterceptor
  2. 把之前的response附加上去,并把body置為空
  3. 后續(xù)的狀態(tài)碼處理

下一個(gè)執(zhí)行的是BridgeInterceptor公般。

BridgeInterceptor
@Override
  public Response intercept(Chain chain) throws IOException {
    Request userRequest = chain.request();
    Request.Builder requestBuilder = userRequest.newBuilder();

    RequestBody body = userRequest.body(); // 獲取請(qǐng)求體
    if (body != null) {
      MediaType contentType = body.contentType();
      //請(qǐng)求頭:Content-Type
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

      //請(qǐng)求頭:長(zhǎng)度
      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");
      }
    }

    //請(qǐng)求頭:主域名
    if (userRequest.header("Host") == null) {
      requestBuilder.header("Host", hostHeader(userRequest.url(), false));
    }

    if (userRequest.header("Connection") == null) {
      requestBuilder.header("Connection", "Keep-Alive");
    }

    // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
    // the transfer stream.
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");
    }

    //cookie
    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
      requestBuilder.header("Cookie", cookieHeader(cookies));
    }

    // okhttp 版本
    if (userRequest.header("User-Agent") == null) {
      requestBuilder.header("User-Agent", Version.userAgent());
    }

    //1
    Response networkResponse = chain.proceed(requestBuilder.build());

    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

    Response.Builder responseBuilder = networkResponse.newBuilder()
        .request(userRequest);

    if (transparentGzip
        && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
        && HttpHeaders.hasBody(networkResponse)) {
      GzipSource responseBody = new GzipSource(networkResponse.body().source());
      Headers strippedHeaders = networkResponse.headers().newBuilder()
          .removeAll("Content-Encoding")
          .removeAll("Content-Length")
          .build();
      responseBuilder.headers(strippedHeaders);
      String contentType = networkResponse.header("Content-Type");
      responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
    }

    return responseBuilder.build();
  }

這個(gè)攔截器基本上是處理Header的信息万搔。

  1. 執(zhí)行下一個(gè)攔截器即CacheInterceptor
CacheInterceptor
@Override public Response intercept(Chain chain) throws IOException {
    Response cacheCandidate = cache != null
        ? cache.get(chain.request())
        : null;

    long now = System.currentTimeMillis();

    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
    Request networkRequest = strategy.networkRequest;
    Response cacheResponse = strategy.cacheResponse;

    if (cache != null) {
      cache.trackResponse(strategy);
    }

    if (cacheCandidate != null && cacheResponse == null) {
      closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
    }

    // If we're forbidden from using the network and the cache is insufficient, fail.
    //1
    if (networkRequest == null && cacheResponse == null) {
      return new Response.Builder()
          .request(chain.request())
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(Util.EMPTY_RESPONSE)
          .sentRequestAtMillis(-1L)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build();
    }

    // If we don't need the network, we're done.
    // 2
    if (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }

    Response networkResponse = null;
    try {
      // 3
      networkResponse = chain.proceed(networkRequest);
    } finally {
      // If we're crashing on I/O or otherwise, don't leak the cache body.
      if (networkResponse == null && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }

    // If we have a cache response too, then we're doing a conditional get.
    // 4
    if (cacheResponse != null) {
      if (networkResponse.code() == HTTP_NOT_MODIFIED) {
        Response response = cacheResponse.newBuilder()
            .headers(combine(cacheResponse.headers(), networkResponse.headers()))
            .sentRequestAtMillis(networkResponse.sentRequestAtMillis())
            .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build();
        networkResponse.body().close();

        // Update the cache after combining headers but before stripping the
        // Content-Encoding header (as performed by initContentStream()).
        cache.trackConditionalCacheHit();
        cache.update(cacheResponse, response);
        return response;
      } else {
        closeQuietly(cacheResponse.body());
      }
    }

    Response response = networkResponse.newBuilder()
        .cacheResponse(stripBody(cacheResponse))
        .networkResponse(stripBody(networkResponse))
        .build();

    if (cache != null) {
      if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
        // Offer this request to the cache.
        CacheRequest cacheRequest = cache.put(response);
        return cacheWritingResponse(cacheRequest, response);
      }

      if (HttpMethod.invalidatesCache(networkRequest.method())) {
        try {
          cache.remove(networkRequest);
        } catch (IOException ignored) {
          // The cache cannot be written.
        }
      }
    }

    return response;
  }

這個(gè)攔截器主要是緩存相關(guān)的。

  1. 如果禁止使用網(wǎng)絡(luò)官帘,并且緩存沒(méi)有則失敗.直接拋出504網(wǎng)關(guān)超時(shí)
  2. 如果沒(méi)有網(wǎng)絡(luò)并且有緩存,直接從cache構(gòu)造一個(gè)Response,并且請(qǐng)求結(jié)束.
  3. 執(zhí)行下一個(gè)攔截器瞬雹,ConnectInterceptor。
  4. 如果我們的緩存有一個(gè)response刽虹,那么將根據(jù)條件來(lái)判斷獲刃锇啤: 如果是304直接從緩存構(gòu)造
ConnectInterceptor
@Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    StreamAllocation streamAllocation = realChain.streamAllocation();

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    RealConnection connection = streamAllocation.connection();

    //繼續(xù)下一個(gè)攔截器
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }

很簡(jiǎn)單的一個(gè)攔截器打開(kāi)一個(gè)到目標(biāo)服務(wù)器的連接,并繼續(xù)下一個(gè)攔截器

CallServerInterceptor
@Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    HttpCodec httpCodec = realChain.httpStream();
    StreamAllocation streamAllocation = realChain.streamAllocation();
    RealConnection connection = (RealConnection) realChain.connection();
    Request request = realChain.request();

    long sentRequestMillis = System.currentTimeMillis();

    realChain.eventListener().requestHeadersStart(realChain.call());
    httpCodec.writeRequestHeaders(request);
    realChain.eventListener().requestHeadersEnd(realChain.call(), request);

    Response.Builder responseBuilder = null;
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
      // If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
      // Continue" response before transmitting the request body. If we don't get that, return
      // what we did get (such as a 4xx response) without ever transmitting the request body.
      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
        httpCodec.flushRequest();
        realChain.eventListener().responseHeadersStart(realChain.call());
        responseBuilder = httpCodec.readResponseHeaders(true);
      }

      if (responseBuilder == null) {
        // Write the request body if the "Expect: 100-continue" expectation was met.
        realChain.eventListener().requestBodyStart(realChain.call());
        long contentLength = request.body().contentLength();
        CountingSink requestBodyOut =
            new CountingSink(httpCodec.createRequestBody(request, contentLength));
        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);

        request.body().writeTo(bufferedRequestBody);
        bufferedRequestBody.close();
        realChain.eventListener()
            .requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
      } else if (!connection.isMultiplexed()) {
        // If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
        // from being reused. Otherwise we're still obligated to transmit the request body to
        // leave the connection in a consistent state.
        streamAllocation.noNewStreams();
      }
    }

    httpCodec.finishRequest();

    if (responseBuilder == null) {
      realChain.eventListener().responseHeadersStart(realChain.call());
      responseBuilder = httpCodec.readResponseHeaders(false);
    }

    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    realChain.eventListener()
        .responseHeadersEnd(realChain.call(), response);

    int code = response.code();
    if (forWebSocket && code == 101) {
      // Connection is upgrading, but we need to ensure interceptors see a non-null response body.
      response = response.newBuilder()
          .body(Util.EMPTY_RESPONSE)
          .build();
    } else {
      response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();
    }

    if ("close".equalsIgnoreCase(response.request().header("Connection"))
        || "close".equalsIgnoreCase(response.header("Connection"))) {
      streamAllocation.noNewStreams();
    }

    if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
      throw new ProtocolException(
          "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
    }

    return response;
  }

okhttp的最后一個(gè)攔截器。通過(guò)網(wǎng)絡(luò)調(diào)用服務(wù)涌哲。

至此 okhttp的同步調(diào)用 execute()流程走完胖缤。

總結(jié)

前面說(shuō)了攔截器用了責(zé)任鏈設(shè)計(jì)模式,它將請(qǐng)求一層一層向下傳,知道有一層能夠得到Resposne就停止向下傳遞阀圾,然后將response向上面的攔截器傳遞哪廓,然后各個(gè)攔截器會(huì)對(duì)respone進(jìn)行一些處理,最后會(huì)傳到RealCall類中通過(guò)execute來(lái)得到esponse初烘。

異步GET請(qǐng)求過(guò)程

private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    Request request = new Request.Builder()
        .url(url)
        .build();

    client.newCall(request).enqueue(new Callback() {
      @Override 
      public void onFailure(Call call, IOException e) {
        e.printStackTrace();
      }

      @Override 
      public void onResponse(Call call, Response response) throws IOException {
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

        Headers responseHeaders = response.headers();
        for (int i = 0, size = responseHeaders.size(); i < size; i++) {
          System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
        }

        System.out.println(response.body().string());
      }
    });
  }

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

這里通過(guò)dispatcher的enqueue 調(diào)用異步涡真。

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

解釋: 當(dāng)當(dāng)前運(yùn)行中的異步請(qǐng)求數(shù)量小于最大數(shù),并且占用的Host數(shù)量小于最大數(shù)肾筐,則將這個(gè)Call加入runningAsyncCalls哆料,并在線程池中運(yùn)行。否則加入readyAsyncCalls中吗铐。

runningAsyncCalls和readyAsyncCalls ?

/** Ready async calls in the order they'll be run. */
  //正在準(zhǔn)備中的異步請(qǐng)求隊(duì)列
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  //運(yùn)行中的異步請(qǐng)求
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  //同步請(qǐng)求
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

AsyncCall 是在RealCall中的一個(gè)內(nèi)部類》

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

通過(guò)NamedRunnable 中的run執(zhí)行 execute()

這里的Response還是執(zhí)行g(shù)etResponseWithInterceptorChain()和同步里的一樣东亦。
最后通過(guò) responseCallback 回調(diào)回去。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末抓歼,一起剝皮案震驚了整個(gè)濱河市讥此,隨后出現(xiàn)的幾起案子拢锹,更是在濱河造成了極大的恐慌,老刑警劉巖萄喳,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卒稳,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡他巨,警方通過(guò)查閱死者的電腦和手機(jī)充坑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)染突,“玉大人捻爷,你說(shuō)我怎么就攤上這事》萜螅” “怎么了也榄?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)司志。 經(jīng)常有香客問(wèn)我甜紫,道長(zhǎng),這世上最難降的妖魔是什么骂远? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任囚霸,我火速辦了婚禮,結(jié)果婚禮上激才,老公的妹妹穿的比我還像新娘拓型。我一直安慰自己,他們只是感情好瘸恼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布劣挫。 她就那樣靜靜地躺著,像睡著了一般钞脂。 火紅的嫁衣襯著肌膚如雪揣云。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天冰啃,我揣著相機(jī)與錄音邓夕,去河邊找鬼。 笑死阎毅,一個(gè)胖子當(dāng)著我的面吹牛焚刚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扇调,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼矿咕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起碳柱,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤捡絮,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后莲镣,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體福稳,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年瑞侮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了的圆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡半火,死狀恐怖越妈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情钮糖,我是刑警寧澤梅掠,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站藐鹤,受9級(jí)特大地震影響瓤檐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜娱节,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望祭示。 院中可真熱鬧肄满,春花似錦、人聲如沸质涛。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)汇陆。三九已至怒炸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間毡代,已是汗流浹背阅羹。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留教寂,地道東北人捏鱼。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像酪耕,于是被迫代替她去往敵國(guó)和親导梆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)看尼,斷路器递鹉,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • 參考資源 官網(wǎng) 國(guó)內(nèi)博客 GitHub官網(wǎng) 鑒于一些關(guān)于OKHttp3源碼的解析文檔過(guò)于碎片化,本文系統(tǒng)的藏斩,由淺入...
    風(fēng)骨依存閱讀 12,506評(píng)論 11 82
  • OkHttp源碼的samples的簡(jiǎn)單使用的示例: public static void main(String....
    _warren閱讀 749評(píng)論 0 1
  • 關(guān)于okhttp是一款優(yōu)秀的網(wǎng)絡(luò)請(qǐng)求框架梳虽,關(guān)于它的源碼分析文章有很多,這里分享我在學(xué)習(xí)過(guò)程中讀到的感覺(jué)比較好的文章...
    蕉下孤客閱讀 3,602評(píng)論 2 38
  • 最近我又要開(kāi)始準(zhǔn)備CATTI的二級(jí)筆譯了灾茁,感覺(jué)長(zhǎng)路漫漫窜觉。五月底的考試,現(xiàn)在剩下的時(shí)間不多了北专,因?yàn)橐獟伻ミ^(guò)年的假期禀挫,...
    逆風(fēng)向橘子閱讀 6,437評(píng)論 0 0