學(xué)習(xí)筆記OkHttp

學(xué)習(xí)一下OkHttp原理章姓,探究他發(fā)送請(qǐng)求的過(guò)程
合理的跳過(guò)了一些內(nèi)容秃殉,比如DNS、Cookie咪笑、Protocol可帽、okio
OkHttp版本3.14.9

btn.setOnClickListener(v -> {
    new Thread(() -> {
        OkHttpClient client = new OkHttpClient.Builder().build();
        Request request = new Request.Builder()
                .url("這里是一個(gè)能訪問(wèn)的url")  
                .build();
        Call call = client.newCall(request);
        try{
            //同步請(qǐng)求
            Response response = call.execute();
            System.out.println(response.body().string());
        }catch(IOException e){
            e.printStackTrace();
        }
    }).start();


    OkHttpClient client = new OkHttpClient.Builder().build();
                Request request = new Request.Builder()
                        .url("這里是一個(gè)能訪問(wèn)的url")
                        .build();
                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());
                        }
                    });



});

隨便寫(xiě)了一個(gè)按鈕,定義 OkHttpClient 蒲肋、 Request 蘑拯、 Call, 然后同步請(qǐng)求,寫(xiě)了一個(gè)最少的http代碼請(qǐng)求兜粘,返回 Response 輸出body
2塊內(nèi)容一個(gè)是同步請(qǐng)求申窘,一個(gè)是異步請(qǐng)求,同步請(qǐng)求不加線程會(huì)拋出異常

開(kāi)始
OkHttpClient.Builder()

看到 OkHttpClient.Builder() 我已經(jīng)不想開(kāi)了孔轴,肯定是初始各種值
build()各種賦值剃法,然后返回一個(gè) OkHttpClient 對(duì)象

Builder(OkHttpClient okHttpClient) {
  this.dispatcher = okHttpClient.dispatcher;//調(diào)度器
  //..
  this.connectionPool = okHttpClient.connectionPool;
  //..
  this.callTimeout = okHttpClient.callTimeout;
  this.connectTimeout = okHttpClient.connectTimeout;
  this.readTimeout = okHttpClient.readTimeout;
  this.writeTimeout = okHttpClient.writeTimeout;
  this.pingInterval = okHttpClient.pingInterval;
}

只留關(guān)鍵的,看名字大概都能知道是什么了
調(diào)度器路鹰,連接池贷洲,call超時(shí),連接超時(shí)等等晋柱,其他的基本也能根據(jù)名字看出來(lái)是干什么的

Request.Builder()
public static class Builder {
  @Nullable HttpUrl url;
  String method;
  Headers.Builder headers;
  @Nullable RequestBody body;

  Map<Class<?>, Object> tags = Collections.emptyMap();

  public Builder() {
    this.method = "GET";
    this.headers = new Headers.Builder();
  }
}

一個(gè)請(qǐng)求包含url优构、methodheadersbody,默認(rèn)GET

client.newCall(request)
@Override public Call newCall(Request request) {
  return RealCall.newRealCall(this, request, false);
}

static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
  RealCall call = new RealCall(client, originalRequest, forWebSocket);
  call.transmitter = new Transmitter(client, call);
  return call;
}

根據(jù) newCall() 返回了一個(gè) RealCall 對(duì)象,還new了一個(gè)Transmitter發(fā)射器雁竞,對(duì)象交給了call
看一下RealCall和Transmitter構(gòu)造函數(shù)

private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
  this.client = client;
  this.originalRequest = originalRequest;
  this.forWebSocket = forWebSocket;
}
public Transmitter(OkHttpClient client, Call call) {
  this.client = client;
  this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool());
  this.call = call;
  this.eventListener = client.eventListenerFactory().create(call);
  this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
}

也是簡(jiǎn)單的初始化钦椭,不過(guò)能看出這個(gè)RealCall已經(jīng)有了發(fā)射器拧额,并且里面有連接池了

call.execute() 同步請(qǐng)求

關(guān)鍵部分,先看call.execute()彪腔,同步執(zhí)行侥锦,根據(jù)安卓機(jī)制必須在子線程

@Override public Response execute() throws IOException {
  //保證只有一個(gè)執(zhí)行
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  transmitter.timeoutEnter();
  transmitter.callStart();
  try {
    client.dispatcher().executed(this);
    return getResponseWithInterceptorChain();
  } finally {
    client.dispatcher().finished(this);
  }
}

//dispatcher的executed, 這里把RealCall放到了同步隊(duì)列里
synchronized void executed(RealCall call) {
  runningSyncCalls.add(call);
}

getResponseWithInterceptorChain() 是庫(kù)的最關(guān)鍵代碼,直接貼代碼
interceptor 是攔截器的意思

Response getResponseWithInterceptorChain() throws IOException {
  //創(chuàng)建了一個(gè)攔截器List,然后添加了寫(xiě)攔截器對(duì)象
  List<Interceptor> interceptors = new ArrayList<>();
  //這是自定義的 先不管
  interceptors.addAll(client.interceptors());
  //重定向攔截器
  interceptors.add(new RetryAndFollowUpInterceptor(client));
  //橋攔截器
  interceptors.add(new BridgeInterceptor(client.cookieJar()));
  //緩存攔截器
  interceptors.add(new CacheInterceptor(client.internalCache()));
  //連接攔截器
  interceptors.add(new ConnectInterceptor(client));
  if (!forWebSocket) {
    interceptors.addAll(client.networkInterceptors());
  }
  //呼叫服務(wù)攔截器德挣。恭垦。。
  interceptors.add(new CallServerInterceptor(forWebSocket));

  //正真串聯(lián)攔截器的地方
  Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
      originalRequest, this, client.connectTimeoutMillis(),
      client.readTimeoutMillis(), client.writeTimeoutMillis());

  boolean calledNoMoreExchanges = false;
  try {
    //這里是正真的把攔截器串聯(lián)起來(lái)的地方 格嗅,并返回Response對(duì)象
    Response response = chain.proceed(originalRequest);
    if (transmitter.isCanceled()) {
      closeQuietly(response);
      throw new IOException("Canceled");
    }
    return response;
  } catch (IOException e) {
    calledNoMoreExchanges = true;
    throw transmitter.noMoreExchanges(e);
  } finally {
    if (!calledNoMoreExchanges) {
      transmitter.noMoreExchanges(null);
    }
  }
}

看看是怎么連起來(lái)的
chain.proceed(originalRequest) 執(zhí)行攔截器方法

public final class RealInterceptorChain implements Interceptor.Chain {
  @Override public Response proceed(Request request) throws IOException {
    return proceed(request, transmitter, exchange);
  }

  public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)throws IOException {

    //保留重要代碼

    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);


    return response;
  }
}

可以看到 RealInterceptorChain 類(lèi)實(shí)現(xiàn)了 Interceptor.Chain 接口,完成了 proceed(Request request) 方法
在下面的 proceed(...) 中,又new了一個(gè) RealInterceptorChain 把攔截器List等參數(shù)又傳了進(jìn)去番挺,有個(gè)關(guān)鍵的變量 index
也就是說(shuō) 自己new了自己,并告訴new出來(lái)的自己索引+1
在看下面2行獲取了一個(gè)攔截器吗浩,執(zhí)行他的攔截方法interceptor.intercept(next)
這里構(gòu)造了一個(gè) 責(zé)任鏈模式建芙,簡(jiǎn)單理解下責(zé)任鏈模式,有點(diǎn)鏈表結(jié)構(gòu)的感覺(jué)懂扼,但不是鏈表,相當(dāng)于把一個(gè)節(jié)點(diǎn)一個(gè)節(jié)點(diǎn)的連起來(lái)右蒲,當(dāng)輸出第一個(gè)節(jié)點(diǎn)阀湿,會(huì)依次調(diào)用下面一個(gè)節(jié)點(diǎn)輸出內(nèi)容
按著順序來(lái)取第一個(gè)攔截器

1、RetryAndFollowUpInterceptor 重定向攔截器

重定向攔截器:主要負(fù)責(zé)失敗重連瑰妄,但并不是所有失敗都重連

public final class RetryAndFollowUpInterceptor implements Interceptor {
  @Override public Response intercept(Chain chain) throws IOException {
      Request request = chain.request();
      RealInterceptorChain realChain = (RealInterceptorChain) chain;
      Transmitter transmitter = realChain.transmitter();

      int followUpCount = 0;
      Response priorResponse = null;
      while (true) {
        transmitter.prepareToConnect(request);
        //如果取消就拋異常
        if (transmitter.isCanceled()) {
          throw new IOException("Canceled");
        }

        Response response;
        boolean success = false;
        try {
          //使用realChain執(zhí)行下一個(gè)攔截器
          //為什么要直接執(zhí)行下一個(gè)攔截器陷嘴?
          //因?yàn)檫@個(gè)是為重定向做的攔截器,肯定是等請(qǐng)求返回結(jié)果之后再?zèng)Q定是否要重定向
          response = realChain.proceed(request, transmitter, null);
          success = true;
        } catch (RouteException e) {
          // The attempt to connect via a route failed. The request will not have been sent.
          if (!recover(e.getLastConnectException(), transmitter, false, request)) {
            throw e.getFirstConnectException();
          }
          continue;
        }//這里刪了catch间坐,出了異常灾挨,catch肯定是關(guān)閉流

        //如果priorResponse不為null,又newBuilder()
        //把上一個(gè)Response和現(xiàn)在的結(jié)合在一起
        //正常來(lái)說(shuō)第一次肯定是空的
        //prior 先前的竹宋,先前的Response不為null
        if (priorResponse != null) {
          response = response.newBuilder()
              .priorResponse(priorResponse.newBuilder()
                      .body(null)
                      .build())
              .build();
        }

        Exchange exchange = Internal.instance.exchange(response);
        Route route = exchange != null ? exchange.connection().route() : null;
        //檢查是否符合要求
        //這個(gè)方法里是一個(gè)switch劳澄、case去找HttpCode狀態(tài)碼 比如200,404
        Request followUp = followUpRequest(response, route);

        //正常來(lái)說(shuō)應(yīng)該是200 followUpRequest()就會(huì)返回null
        if (followUp == null) {
          if (exchange != null && exchange.isDuplex()) {
            transmitter.timeoutEarlyExit();
          }
          return response;
        }

        RequestBody followUpBody = followUp.body();
        if (followUpBody != null && followUpBody.isOneShot()) {
          return response;
        }

        closeQuietly(response.body());
        if (transmitter.hasExchange()) {
          exchange.detachWithViolence();
        }
        //限制重定向次數(shù)
        if (++followUpCount > MAX_FOLLOW_UPS) {
          throw new ProtocolException("Too many follow-up requests: " + followUpCount);
        }

        request = followUp;
        priorResponse = response;
      }
    }
}

這個(gè)攔截器就是先請(qǐng)求蜈七,請(qǐng)求返回?cái)?shù)據(jù)之后根據(jù)數(shù)據(jù)來(lái)判斷秒拔,是否需要重定向

2、BridgeInterceptor 橋攔截器

這里很長(zhǎng)飒硅,橋攔截器主要用來(lái)添加頭部信息砂缩、編碼方式

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

    RequestBody body = userRequest.body();
    if (body != null) {
      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");
      }
    }

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

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

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

    //這里調(diào)用下一層的攔截器
    Response networkResponse = chain.proceed(requestBuilder.build());
    //下面是處理cookie緩存和GZip的內(nèi)容
    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

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

    //判斷服務(wù)器是否支持GZip,支持交給okio處理
    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");
      //處理之后build 一個(gè)新的Response
      responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
    }

    return responseBuilder.build();
  }
}

這里就是3段內(nèi)容三娩,增加頭信息庵芭、調(diào)用下一層攔截器、處理緩存和GZip

3雀监、CacheInterceptor 緩存攔截器

緩存攔截器双吆,顧名思義處理緩存

public final class CacheInterceptor implements Interceptor {
  @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.
     }

     //注釋寫(xiě)明了,如果沒(méi)網(wǎng)和沒(méi)緩存 直接返回失敗
     // If we're forbidden from using the network and the cache is insufficient, fail.
     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();
     }
     //這里沒(méi)網(wǎng)
     // If we don't need the network, we're done.
     if (networkRequest == null) {
       return cacheResponse.newBuilder()
           .cacheResponse(stripBody(cacheResponse))
           .build();
     }

     Response networkResponse = null;
     try {
       //調(diào)用下一層攔截器
       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.
     //如果有緩存并且code為304,使用緩存內(nèi)容
     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;
   }
}

這一層也很明確伊诵,專(zhuān)門(mén)處理緩存单绑,有個(gè)關(guān)鍵cache對(duì)象,如果最開(kāi)始o(jì)khttp初始化曹宴,賦值了搂橙,則會(huì)使用這個(gè)緩存,如果沒(méi)賦值則不會(huì)使用笛坦。

4区转、ConnectInterceptor 連接攔截器

連接攔截器,這層是關(guān)鍵內(nèi)容版扩,也最復(fù)雜废离,負(fù)責(zé)與服務(wù)器建立連接

public final class ConnectInterceptor implements Interceptor {
  public final OkHttpClient client;

  @Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    Transmitter transmitter = realChain.transmitter();

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks);

    return realChain.proceed(request, transmitter, exchange);
  }
}
//前面只是獲取對(duì)象
//關(guān)鍵 發(fā)射機(jī) transmitter.newExchange(chain, doExtensiveHealthChecks)

public final class Transmitter {
  //這個(gè)exchangeFinder也是new出來(lái)的
  private ExchangeFinder exchangeFinder;

  //這里看方法是返回一個(gè)Exchange對(duì)象
  //我也不知道為什么要叫這個(gè)名字,歷史版本我也沒(méi)看過(guò)
  Exchange newExchange(Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
    synchronized (connectionPool) {
      if (noMoreExchanges) {
        throw new IllegalStateException("released");
      }
      if (exchange != null) {
        throw new IllegalStateException("cannot make a new request because the previous response "
            + "is still open: please call response.close()");
      }
    }
    //exchangeFinder礁芦,exchange查找器
    ExchangeCodec codec = exchangeFinder.find(client, chain, doExtensiveHealthChecks);
    Exchange result = new Exchange(this, call, eventListener, exchangeFinder, codec);

    synchronized (connectionPool) {
      this.exchange = result;
      this.exchangeRequestDone = false;
      this.exchangeResponseDone = false;
      return result;
    }
  }
}
//Exchange查找器
final class ExchangeFinder {

  public ExchangeCodec find(
        OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
      int connectTimeout = chain.connectTimeoutMillis();
      int readTimeout = chain.readTimeoutMillis();
      int writeTimeout = chain.writeTimeoutMillis();
      int pingIntervalMillis = client.pingIntervalMillis();
      boolean connectionRetryEnabled = client.retryOnConnectionFailure();
      //上面只是賦值 連接時(shí)間 讀取時(shí)間超時(shí)等等
      try {
        //獲取一個(gè)健康的連接
        RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
            writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
        return resultConnection.newCodec(client, chain);
      } catch (RouteException e) {
        trackFailure();
        throw e;
      } catch (IOException e) {
        trackFailure();
        throw new RouteException(e);
      }
    }
    //尋找一個(gè)健康的連接
    private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,int writeTimeout, int pingIntervalMillis, boolean connectionRetryEnabled,boolean doExtensiveHealthChecks) throws IOException {
      while (true) {
        //while ture 去尋找一個(gè) 連接
        //這里死循環(huán)去找鏈接的連接 可能是有問(wèn)題的連接
        RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
            pingIntervalMillis, connectionRetryEnabled);

        synchronized (connectionPool) {
          //這里鎖 一下 判斷 蜻韭,如果是全新的連接就直接返回
          if (candidate.successCount == 0 && !candidate.isMultiplexed()) {
            return candidate;
          }
        }

        //這里判斷連接是否健康,無(wú)非是socket沒(méi)有關(guān)閉柿扣,等等
        if (!candidate.isHealthy(doExtensiveHealthChecks)) {
          candidate.noNewExchanges();
          continue;
        }

        return candidate;
      }
    }

  //最長(zhǎng)代碼肖方,一點(diǎn)點(diǎn)看
vate RealConnection findConnection(int connectTimeout, int  dTimeout, int writeTimeout,
nt pingIntervalMillis, boolean connectionRetryEnabled) throws OException {
  boolean foundPooledConnection = false;
  RealConnection result = null;
  Route selectedRoute = null;
  RealConnection releasedConnection;
  Socket toClose;
  synchronized (connectionPool) {
    if (transmitter.isCanceled()) throw new IOException("Canceled");
    hasStreamFailure = false; // This is a fresh attempt.

    //這里鎖池子,看看當(dāng)前發(fā)射機(jī)transmitter里面的連接能不能用
    releasedConnection = transmitter.connection;
    toClose = transmitter.connection != null &&   transmitter.connection.noNewExchanges
    ? transmitter.releaseConnectionNoEvents()
    : null;

    if (transmitter.connection != null) {
      //這里判斷有點(diǎn)特別
      //發(fā)射機(jī)連接不為空 能用 就賦值給result對(duì)象
      result = transmitter.connection;
      releasedConnection = null;
    }
    //當(dāng)然result為空就要從連接池取
    if (result == null) {
      //里面就是循環(huán)連接池未状,循環(huán)取俯画,當(dāng)然 也有可能取不到
      //取不到下面會(huì)new的,第一次肯定取不到
      if(connectionPool.transmitterAcquirePooledConnection(address,  transmitter, null, false)) {
        foundPooledConnection = true;
        result = transmitter.connection;
        } else if (nextRouteToTry != null) {
          selectedRoute = nextRouteToTry;
          nextRouteToTry = null;
          } else if (retryCurrentRoute()) {
            selectedRoute = transmitter.connection.route();
          }
        }
      }
      closeQuietly(toClose);

      if (releasedConnection != null) {
        eventListener.connectionReleased(call, releasedConnection);
      }
      if (foundPooledConnection) {
        eventListener.connectionAcquired(call, result);
      }
      if (result != null) {
        //到這里result不為空  則直接返回發(fā)射機(jī)里的 連接
        return result;
      }

      // If we need a route selection, make one. This is a blocking operation.
      boolean newRouteSelection = false;
      if (selectedRoute == null && (routeSelection == null ||   !routeSelection.hasNext())) {
        newRouteSelection = true;
        routeSelection = routeSelector.next();
      }

      List<Route> routes = null;
      synchronized (connectionPool) {
        if (transmitter.isCanceled()) throw new IOException("Canceled");

        if (newRouteSelection) {
          //獲取路由表司草,再次嘗試從連接池里取連接
          routes = routeSelection.getAll();
          if (connectionPool.transmitterAcquirePooledConnection(
            address, transmitter, routes, false)) {
              foundPooledConnection = true;
              //取到了就賦值給result
              result = transmitter.connection;
            }
          }

          if (!foundPooledConnection) {
            if (selectedRoute == null) {
              selectedRoute = routeSelection.next();
            }

            //各種都取不到 new了
            result = new RealConnection(connectionPool, selectedRoute);
            connectingConnection = result;
          }
        }

        //這里是回調(diào) 艰垂,獲取連接后調(diào)用的
        if (foundPooledConnection) {
          eventListener.connectionAcquired(call, result);
          return result;
        }

        //到這里肯定是新連接了,開(kāi)始握手
        result.connect(connectTimeout, readTimeout, writeTimeout,   pingIntervalMillis,
          connectionRetryEnabled, call, eventListener);
          connectionPool.routeDatabase.connected(result.route());

        Socket socket = null;
        synchronized (connectionPool) {
          connectingConnection = null;
          //這里又嘗試去取連接
          if(connectionPool.transmitterAcquirePooledConnection(address,  transmitter, routes, true)) {
              result.noNewExchanges = true;
              socket = result.socket();
              result = transmitter.connection;

              // It's possible for us to obtain a coalesced connection that is  immediately unhealthy. In
              // that case we will retry the route we just successfully connected   with.
              nextRouteToTry = selectedRoute;
              } else {
                connectionPool.put(result);
                transmitter.acquireConnectionNoEvents(result);
              }
            }
            closeQuietly(socket);

            eventListener.connectionAcquired(call, result);
            return result;
          }
    //到這里一個(gè)連接就找到了
    //返回上面 埋虹,根據(jù)這個(gè)連接去判斷他是否健康猜憎,不健康就再取
}

1、從transmitter中取吨岭,取到就返回
2拉宗、如果取不到從ConnectionPool中取,取到就返回
3辣辫、遍歷路由地址旦事、再?gòu)腃onnectionPool中取
4、創(chuàng)建新的Connection
5急灭、用新的Connection進(jìn)行握手
到這里 從find()->findHealthyConnection()->findConnection()很清晰
這里我有個(gè)不明白的地方姐浮,如果大佬看到了可以為我解釋?zhuān)嚎赡苓@里偏向網(wǎng)絡(luò)了,不太明白這里的路由表Route有什么作用葬馋。
再來(lái)看一下 握手

result.connect(...) 握手
public void connect(int connectTimeout, int readTimeout, int writeTimeout,int pingIntervalMillis, boolean connectionRetryEnabled, Call call,EventListener eventListener) {
    if (protocol != null) throw new IllegalStateException("already connected");

    //去掉一些賦值和一些判斷卖鲤,如果有問(wèn)題會(huì)拋出路由異常
    //判斷客戶端是否啟用明文通信等等

    while (true) {
      try {
        if (route.requiresTunnel()) {
          //如果有通道肾扰,去進(jìn)行連接通道 里面還是會(huì)連接socket
          connectTunnel(connectTimeout, readTimeout, writeTimeout, call, eventListener);
          if (rawSocket == null) {
            //成功就跳出
            break;
          }
        } else {
          //關(guān)鍵 連接socket
          connectSocket(connectTimeout, readTimeout, call, eventListener);
        }
        //定制協(xié)議
        //這里面賦值一下協(xié)議,這時(shí)候socket已經(jīng)建立了
        //已經(jīng)知道服務(wù)器用的什么協(xié)議了
        establishProtocol(connectionSpecSelector, pingIntervalMillis, call, eventListener);
        //listener 回調(diào) 告訴我們 連接完成
        //這里在Okhttp創(chuàng)建的時(shí)候 做一些日志操作
        eventListener.connectEnd(call, route.socketAddress(), route.proxy(), protocol);
        break;
      } catch (IOException e) {
        //一些關(guān)閉流的操作
     }

    if (route.requiresTunnel() && rawSocket == null) {
      ProtocolException exception = new ProtocolException("Too many tunnel connections attempted: "
          + MAX_TUNNEL_ATTEMPTS);
      throw new RouteException(exception);
    }

    if (http2Connection != null) {
      synchronized (connectionPool) {
        allocationLimit = http2Connection.maxConcurrentStreams();
      }
    }
}

//socket連接
connectSocket(connectTimeout, readTimeout, call, eventListener);
private void connectSocket(int connectTimeout, int readTimeout, Call call,
    EventListener eventListener) throws IOException {
  Proxy proxy = route.proxy();
  Address address = route.address();

  rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP
      ? address.socketFactory().createSocket()
      : new Socket(proxy);
  //連接開(kāi)始
  eventListener.connectStart(call, route.socketAddress(), proxy);
  rawSocket.setSoTimeout(readTimeout);
  try {
    //連接操作
    //get判斷是android平臺(tái)還是java平臺(tái),再里面反射了一些SSL的底層實(shí)現(xiàn)類(lèi)
    //connectSocket里面就是socket連接了
    Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout);
  } catch (ConnectException e) {
    ConnectException ce = new ConnectException("Failed to connect to " + route.socketAddress());
    ce.initCause(e);
    throw ce;
}

ConnectInterceptor 連接攔截器,這里很長(zhǎng)蛋逾,做的事情也很明確
1集晚、從連接池取連接
2、如果是新的連接区匣,socket建立連接
其實(shí)這里的握手操作意思是建立Socket操作偷拔,Socket是一個(gè)套接字,是一個(gè)通信連接的對(duì)象亏钩,socket屬于傳輸層莲绰,正真建立三次握手的是在這一層,不是在我們寫(xiě)的引用層姑丑。

5蛤签、CallServerInterceptor 呼叫服務(wù)器攔截器

最后一層,請(qǐng)求網(wǎng)絡(luò)

public final class CallServerInterceptor implements Interceptor {

  @Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Exchange exchange = realChain.exchange();
    Request request = realChain.request();

    long sentRequestMillis = System.currentTimeMillis();
    //向socket頭寫(xiě)入信息
    exchange.writeRequestHeaders(request);

    boolean responseHeadersStarted = false;
    Response.Builder responseBuilder = null;
    //這里判斷是否有Body
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
      //當(dāng)socket連接服務(wù)器后栅哀,就已經(jīng)有狀態(tài)碼了
      //100 該狀態(tài)碼 說(shuō)明服務(wù)器已經(jīng)接收到了 請(qǐng)求的初始部分
      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
        exchange.flushRequest();
        responseHeadersStarted = true;
        exchange.responseHeadersStart();
        responseBuilder = exchange.readResponseHeaders(true);
      }

      if (responseBuilder == null) {
        //這里判斷全雙工  默認(rèn)false
        if (request.body().isDuplex()) {
          // Prepare a duplex body so that the application can send a request body later.
          exchange.flushRequest();
          BufferedSink bufferedRequestBody = Okio.buffer(
              exchange.createRequestBody(request, true));
          request.body().writeTo(bufferedRequestBody);
        } else {
          // Write the request body if the "Expect: 100-continue" expectation was met.
          BufferedSink bufferedRequestBody = Okio.buffer(
              exchange.createRequestBody(request, false));
          request.body().writeTo(bufferedRequestBody);
          //
          bufferedRequestBody.close();
        }
      } else {
        exchange.noRequestBody();
        if (!exchange.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.
          exchange.noNewExchangesOnConnection();
        }
      }
    } else {
      exchange.noRequestBody();
    }

    if (request.body() == null || !request.body().isDuplex()) {
      //完成網(wǎng)絡(luò)的寫(xiě)入
      exchange.finishRequest();
    }

    if (!responseHeadersStarted) {
      //回調(diào)listener
      exchange.responseHeadersStart();
    }

    if (responseBuilder == null) {
      //讀取Response  在這個(gè)里面正真的 調(diào)用他自己的okio 讀取數(shù)據(jù)
      responseBuilder = exchange.readResponseHeaders(false);
    }
    //數(shù)據(jù)已經(jīng)回來(lái)了到這里 后面就是一些小判斷了
    Response response = responseBuilder
        .request(request)
        .handshake(exchange.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    int code = response.code();
    if (code == 100) {
      // server sent a 100-continue even though we did not request one.
      // try again to read the actual response
      response = exchange.readResponseHeaders(false)
          .request(request)
          .handshake(exchange.connection().handshake())
          .sentRequestAtMillis(sentRequestMillis)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build();

      code = response.code();
    }

    exchange.responseHeadersEnd(response);

    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(exchange.openResponseBody(response))
          .build();
    }

    if ("close".equalsIgnoreCase(response.request().header("Connection"))
        || "close".equalsIgnoreCase(response.header("Connection"))) {
      exchange.noNewExchangesOnConnection();
    }

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

    return response;
  }
}

到這里 Response已經(jīng)回來(lái)震肮,數(shù)據(jù)也讀取完畢。最后返回 response
這里5個(gè)攔截器已經(jīng)全部走完
回顧一下5個(gè)攔截器
1昌屉、RetryAndFollowUpInterceptor 重定向攔截器
2钙蒙、BridgeInterceptor 橋攔截器
3、CacheInterceptor 緩存攔截器
4间驮、ConnectInterceptor 連接攔截器
5、CallServerInterceptor 呼叫服務(wù)攔截器
這5個(gè)攔截器依次從上往下執(zhí)行马昨,最后再返回
以上記錄的是 同步請(qǐng)求方法

call.enqueue(new Callback(){..} ) 異步請(qǐng)求
@Override public void enqueue(Callback responseCallback) {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  transmitter.callStart();
  //創(chuàng)建了一個(gè)AsynCall對(duì)象
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
//調(diào)度器的dispatcher方法
void enqueue(AsyncCall call) {
  synchronized (this) {
    //鎖住對(duì)象放入 readyAsyncCalls 隊(duì)列中
    readyAsyncCalls.add(call);

    if (!call.get().forWebSocket) {
      AsyncCall existingCall = findExistingCallWithHost(call.host());
      if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
    }
  }
  //執(zhí)行
  promoteAndExecute();
}

//執(zhí)行
private boolean promoteAndExecute() {

  List<AsyncCall> executableCalls = new ArrayList<>();
  boolean isRunning;
  synchronized (this) {
    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall asyncCall = i.next();

      if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
      if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.

      i.remove();
      asyncCall.callsPerHost().incrementAndGet();
      //鎖住對(duì)象時(shí)的 臨時(shí)隊(duì)列
      executableCalls.add(asyncCall);
      //鎖住對(duì)象竞帽,把準(zhǔn)備好的AsyncCall 放到runningAsyncCalls隊(duì)列里
      //runningAsyncCalls是正在執(zhí)行的隊(duì)列
      runningAsyncCalls.add(asyncCall);
    }
    isRunning = runningCallsCount() > 0;
  }

  for (int i = 0, size = executableCalls.size(); i < size; i++) {
    AsyncCall asyncCall = executableCalls.get(i);
    //循環(huán)這個(gè)執(zhí)行臨時(shí)隊(duì)列的
    //根據(jù)安卓的機(jī)制還是需要在子線程里請(qǐng)求網(wǎng)絡(luò)
    //executorService()是個(gè)線程池
    asyncCall.executeOn(executorService());
  }

  return isRunning;
}
//看一下AsyncCall結(jié)構(gòu) 是個(gè)內(nèi)部類(lèi)
final class RealCall implements Call {
  final class AsyncCall extends NamedRunnable {
  }
}
//在看一下NamedRunnable,繼承了Runnable,他的run方法里執(zhí)行了execute()
public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}
//既然執(zhí)行了execute()方法 打開(kāi)asyncCall.executeOn(executorService());

void executeOn(ExecutorService executorService) {

      boolean success = false;
      try {
        //executorService線程池對(duì)象 執(zhí)行this
        //這個(gè)this就是AsyncCall類(lèi)
        //也就是線程池執(zhí)行 run方法鸿捧,上面的run方法又執(zhí)行了execute()

        executorService.execute(this);
        success = true;
      } catch (RejectedExecutionException e) {

      } finally {

      }
}
//所以只要看  AsyncCall 完成的 NamedRunnable的 execute()方法
@Override protected void execute() {
  boolean signalledCallback = false;
  transmitter.timeoutEnter();
  try {
    Response response = getResponseWithInterceptorChain();
    signalledCallback = true;
    responseCallback.onResponse(RealCall.this, response);
  } catch (IOException e) {

  } finally {

  }
}

最后又執(zhí)行了 getResponseWithInterceptorChain() 方法屹篓,執(zhí)行5個(gè)攔截器,返回
這里代碼很長(zhǎng)匙奴,關(guān)鍵內(nèi)容就在5個(gè)攔截器
OkHttp還有一個(gè)比較關(guān)鍵的內(nèi)容就是連接池堆巧,暫時(shí)不寫(xiě)了。
貼個(gè)圖加深印象泼菌,看源碼不太清晰的時(shí)候谍肤,畫(huà)個(gè)思維導(dǎo)圖或者畫(huà)一個(gè)重要類(lèi)的 類(lèi)圖基本上代碼就很清晰了

OkHttp.png

我也看到了很多不會(huì)內(nèi)容,我會(huì)繼續(xù)深入的學(xué)習(xí)
如果你看到這里哗伯,覺(jué)得寫(xiě)的還可以荒揣,請(qǐng)給我贊吧~!??

學(xué)藝不精焊刹,如果內(nèi)容有錯(cuò)誤請(qǐng)及時(shí)聯(lián)系我系任,我及時(shí)改正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末恳蹲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子俩滥,更是在濱河造成了極大的恐慌嘉蕾,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件霜旧,死亡現(xiàn)場(chǎng)離奇詭異错忱,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)颁糟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)航背,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人棱貌,你說(shuō)我怎么就攤上這事玖媚。” “怎么了婚脱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵今魔,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我障贸,道長(zhǎng)错森,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任篮洁,我火速辦了婚禮涩维,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘袁波。我一直安慰自己瓦阐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布篷牌。 她就那樣靜靜地躺著睡蟋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪枷颊。 梳的紋絲不亂的頭發(fā)上戳杀,一...
    開(kāi)封第一講書(shū)人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音夭苗,去河邊找鬼信卡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛听诸,可吹牛的內(nèi)容都是我干的坐求。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼晌梨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼桥嗤!你這毒婦竟也來(lái)了须妻?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤泛领,失蹤者是張志新(化名)和其女友劉穎荒吏,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體渊鞋,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绰更,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锡宋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片儡湾。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖执俩,靈堂內(nèi)的尸體忽然破棺而出徐钠,到底是詐尸還是另有隱情,我是刑警寧澤役首,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布尝丐,位于F島的核電站,受9級(jí)特大地震影響衡奥,放射性物質(zhì)發(fā)生泄漏爹袁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一矮固、第九天 我趴在偏房一處隱蔽的房頂上張望失息。 院中可真熱鬧,春花似錦档址、人聲如沸根时。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至确虱,卻和暖如春含友,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背校辩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工窘问, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宜咒。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓惠赫,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親故黑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子儿咱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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