OkHttp源码分析

OkHttp源码分析

1、基本使用

// to create a shared instance with the custom settings
// 共享client实例
 public final OkHttpClient client = new OkHttpClient.Builder()
    // 设置拦截器
    .addInterceptor(new HttpLoggingInterceptor())
    // 设置缓存路径以及缓存大小
    .cache(new Cache(cacheDir, cacheSize))
    .build();

// You can customize a shared OkHttpClient instance with {@link #newBuilder()}. This builds a client that shares the same connection pool, thread pools, and configuration. Use the buildermethods to configure the derived client for a specific purpose.

// 共享client连接池、线程池和配置
    public final OkHttpClient client = new OkHttpClient();
     OkHttpClient eagerClient = client.newBuilder()
        // 设置读取时间
        .readTimeout(500, TimeUnit.MILLISECONDS)
        .build();
    Response response = eagerClient.newCall(request).execute();

    // 关闭executorService
    client.dispatcher().executorService().shutdown();

    // 清空连接池
    client.connectionPool().evictAll();

    // 关闭缓存,如果已经设置了缓存,会导致请求call崩溃
     client.cache().close();
使用client.newBuilder()方式会共享client的相同的连接池、线程池和参数配置,使用new OkHttpClient.Builder()会共享创建的client实例

2、源码分析

首先分析共享client的方式

new OkHttpClient.Builder()
    public Builder() {
      // 异步请求执行政策
      dispatcher = new Dispatcher();
      // http协议
      protocols = DEFAULT_PROTOCOLS;
      // 默认连接规格
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      // 事件监听工厂
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      // 代理选择器
      proxySelector = ProxySelector.getDefault();
      // cookie设置 
      cookieJar = CookieJar.NO_COOKIES;
      // socket工厂
      socketFactory = SocketFactory.getDefault();
      // 主机名认证
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      // 证书pinner
      certificatePinner = CertificatePinner.DEFAULT;
      // 代理身份认证
      proxyAuthenticator = Authenticator.NONE;
      // 身份认证
      authenticator = Authenticator.NONE;
      // 连接池
      connectionPool = new ConnectionPool();
      // DNS
      dns = Dns.SYSTEM;
      // 遵循SSL重定向
      followSslRedirects = true;
      // 遵循重定向
      followRedirects = true;
      // 连接失败重试
      retryOnConnectionFailure = true;
      // 连接超时时间
      connectTimeout = 10_000;
      // 读取超时使劲
      readTimeout = 10_000;
      // 写入超时时间
      writeTimeout = 10_000;
      // ping时间间隔
      pingInterval = 0;
    }
addInterceptor(new HttpLoggingInterceptor())
 /**
     * Returns a modifiable list of interceptors that observe the full span of each call: from
     * before the connection is established (if any) until after the response source is selected
     * (either the origin server, cache, or both).
     */
     // 返回可修改的interceptor集合,interceptor用于观察从established之前到响应资源的全过程,内容包括原始服务器、缓存或者两者都包括
    public List<Interceptor> interceptors() {
      return interceptors;
    }

    public Builder addInterceptor(Interceptor interceptor) {
      if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
      interceptors.add(interceptor);
      return this;
    }

    /**
     * Returns a modifiable list of interceptors that observe a single network request and response.
     * These interceptors must call {@link Interceptor.Chain#proceed} exactly once: it is an error
     * for a network interceptor to short-circuit or repeat a network request.
     */
     // 观察单独的一次请求和响应,对于短路和重复请求会报错
    public List<Interceptor> networkInterceptors() {
      return networkInterceptors;
    }

    public Builder addNetworkInterceptor(Interceptor interceptor) {
      if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
      networkInterceptors.add(interceptor);
      return this;
    }
interceptor和netWorkInterceptor区别
addInterceptor() 添加应用拦截器
不需要担心中间过程的响应,如重定向和重试.
总是只调用一次,即使HTTP响应是从缓存中获取.
观察应用程序的初衷. 不关心OkHttp注入的头信息如: If-None-Match.
允许短路而不调用 Chain.proceed(),即中止调用.
允许重试,使 Chain.proceed()调用多次.

addNetworkInterceptor() 添加网络拦截器
能够操作中间过程的响应,如重定向和重试.
当网络短路而返回缓存响应时不被调用.
只观察在网络上传输的数据.
携带请求来访问连接.
.cache
// 设置响应缓存,用于读写缓存响应数据

  /** Sets the response cache to be used to read and write cached responses. */
    public Builder cache(@Nullable Cache cache) {
      this.cache = cache;
      this.internalCache = null;
      return this;
    }

查看Cache类基本使用

方式一:设置无缓存
 Request request = new Request.Builder()
        .cacheControl(new CacheControl.Builder().noCache().build())
        .url("http://publicobject.com/helloworld.txt")
        .build();
方式二:设置具有超时时间的缓存
 Request request = new Request.Builder()
           .cacheControl(new CacheControl.Builder()
           .maxAge(0, TimeUnit.SECONDS)
           .build())
           .url("http://publicobject.com/helloworld.txt")
           .build();
方式三:设置只读取缓存内容
   Request request = new Request.Builder()
          .cacheControl(new CacheControl.Builder()
              .onlyIfCached()
              .build())
          .url("http://publicobject.com/helloworld.txt")
          .build();
          // 可以根据forceCacheResponse.code()设置是否读取缓存
      Response forceCacheResponse = client.newCall(request).execute();
      if (forceCacheResponse.code() != 504) {
        // The resource was cached! Show it.
      } else {
        // The resource was not cached.
      }
方式四:设置缓存时间为365天
 Request request = new Request.Builder()
       .cacheControl(new CacheControl.Builder()
        .maxStale(365, TimeUnit.DAYS)
        .build())
        .url("http://publicobject.com/helloworld.txt")
        .build();
  }

  构造方法分析

    // 指定文件目录和缓存大小
    public Cache(File directory, long maxSize) {
    this(directory, maxSize, FileSystem.SYSTEM);
  }
    // 通过DiskLruCache.create()方法缓存至磁盘
  Cache(File directory, long maxSize, FileSystem fileSystem) {
    this.cache = DiskLruCache.create(fileSystem, directory, VERSION, ENTRY_COUNT, maxSize);
  }

跟进DiskLruCache.create方法
/**
   * Create a cache which will reside in {@code directory}. This cache is lazily initialized on
   * first access and will be created if it does not exist.
   *
   * @param directory a writable directory
   * @param valueCount the number of values per cache entry. Must be positive.
   * @param maxSize the maximum number of bytes this cache should use to store
   */
  public static DiskLruCache create(FileSystem fileSystem, File directory, int appVersion,
      int valueCount, long maxSize) {
    if (maxSize <= 0) {
      throw new IllegalArgumentException("maxSize <= 0");
    }
    if (valueCount <= 0) {
      throw new IllegalArgumentException("valueCount <= 0");
    }

    // Use a single background thread to evict entries.
    // 使用线程池进行管理,核心线程数为0,非核心线程数为1,存活时间为30秒
    Executor executor = new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS,
        new LinkedBlockingQueue<Runnable>(), Util.threadFactory("OkHttp DiskLruCache", true));
    return new DiskLruCache(fileSystem, directory, appVersion, valueCount, maxSize, executor);
  }

  查看new DiskLruCache构造方法
    // 构造传参
    DiskLruCache(FileSystem fileSystem, File directory, int appVersion, int valueCount, long maxSize,
      Executor executor) {
      // fileSystem
    this.fileSystem = fileSystem;
    // 路径
    this.directory = directory;
    // app版本
    this.appVersion = appVersion;
    // 日志文件
    this.journalFile = new File(directory, JOURNAL_FILE);
    // 临时日志文件
    this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP);
    // 日志文件本分
    this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP);
    // 值数量
    this.valueCount = valueCount;
    // 缓存最大值
    this.maxSize = maxSize;
    // 线程池
    this.executor = executor;
  }


  查看线程池Runnable
    /** Used to run 'cleanupRunnable' for journal rebuilds. */

  private final Runnable cleanupRunnable = new Runnable() {
    public void run() {
      synchronized (DiskLruCache.this) {
        if (!initialized | closed) {
          return; // Nothing to do
        }

        try {
        // 削减大小
          trimToSize();
        } catch (IOException ignored) {
          mostRecentTrimFailed = true;
        }

        try {
          if (journalRebuildRequired()) {
          // 重建Journal
            rebuildJournal();
            redundantOpCount = 0;
          }
        } catch (IOException e) {
          mostRecentRebuildFailed = true;
          journalWriter = Okio.buffer(Okio.blackhole());
        }
      }
    }
  };

  查看trimToSize
   void trimToSize() throws IOException {
    while (size > maxSize) {
     // final LinkedHashMap<String, Entry> lruEntries = new LinkedHashMap<>
    // lruEntries 使用linkedHashMap管理缓存
      Entry toEvict = lruEntries.values().iterator().next();
      // 从末尾移除不常用缓存数据
      removeEntry(toEvict);
    }
    mostRecentTrimFailed = false;
  }


查看 removeEntry(toEvict);

    boolean removeEntry(Entry entry) throws IOException {
    if (entry.currentEditor != null) {
      entry.currentEditor.detach(); // Prevent the edit from completing normally.
    }

    for (int i = 0; i < valueCount; i++) {
      fileSystem.delete(entry.cleanFiles[i]);
      // 将entry.lengths[i]从数据中移除
      size -= entry.lengths[i];
      entry.lengths[i] = 0;
    }
    // 计数器累加
    redundantOpCount++;
    journalWriter.writeUtf8(REMOVE).writeByte(' ').writeUtf8(entry.key).writeByte('\n');
    // 从linkedHashMap中移除该键
    lruEntries.remove(entry.key);

    if (journalRebuildRequired()) {
    // 如果需要rebuild再次调用线程池执行cleanupRunnable
      executor.execute(cleanupRunnable);
    }

    return true;
  }


 查看 runnable中执行的rebuildJournal()方法

   /**
   * Creates a new journal that omits redundant information. This replaces the current journal if it
   * exists.
   */
   // 创建一个journal,去除了多余的信息,如果存在的话就是用当前的journal进行替换
  synchronized void rebuildJournal() throws IOException {
    if (journalWriter != null) {
      journalWriter.close();
    }

    BufferedSink writer = Okio.buffer(fileSystem.sink(journalFileTmp));
    try {
      writer.writeUtf8(MAGIC).writeByte('\n');
      writer.writeUtf8(VERSION_1).writeByte('\n');
      writer.writeDecimalLong(appVersion).writeByte('\n');
      writer.writeDecimalLong(valueCount).writeByte('\n');
      writer.writeByte('\n');

      for (Entry entry : lruEntries.values()) {
        if (entry.currentEditor != null) {
          writer.writeUtf8(DIRTY).writeByte(' ');
          writer.writeUtf8(entry.key);
          writer.writeByte('\n');
        } else {
          writer.writeUtf8(CLEAN).writeByte(' ');
          writer.writeUtf8(entry.key);
          entry.writeLengths(writer);
          writer.writeByte('\n');
        }
      }
    } finally {
      writer.close();
    }

    if (fileSystem.exists(journalFile)) {
      fileSystem.rename(journalFile, journalFileBackup);
    }
    fileSystem.rename(journalFileTmp, journalFile);
    fileSystem.delete(journalFileBackup);

    journalWriter = newJournalWriter();
    hasJournalErrors = false;
    mostRecentRebuildFailed = false;
  }
build();
 public OkHttpClient build() {
// 直接调用OkHttpClient构造方法构建OkHttpClient实例
      return new OkHttpClient(this);
    }
OkHttpClient构造
  OkHttpClient(Builder builder) {
  // 通过builder中各项参数设置,为创建OkHttpClient相应参数进行赋值操作
    this.dispatcher = builder.dispatcher;
    this.proxy = builder.proxy;
    this.protocols = builder.protocols;
    this.connectionSpecs = builder.connectionSpecs;
    this.interceptors = Util.immutableList(builder.interceptors);
    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
    this.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    this.internalCache = builder.internalCache;
    this.socketFactory = builder.socketFactory;

    boolean isTLS = false;
    for (ConnectionSpec spec : connectionSpecs) {
      isTLS = isTLS || spec.isTls();
    }

    if (builder.sslSocketFactory != null || !isTLS) {
    // 如果设置了sslSocketFactory使用设置的sslSocketFactory
      this.sslSocketFactory = builder.sslSocketFactory;
      this.certificateChainCleaner = builder.certificateChainCleaner;
    } else {
    // 使用默认的systemDefaultSslSocketFactory进行X509认证管理
      X509TrustManager trustManager = systemDefaultTrustManager();
      this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
      this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
    }

    this.hostnameVerifier = builder.hostnameVerifier;
    this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
        certificateChainCleaner);
    this.proxyAuthenticator = builder.proxyAuthenticator;
    this.authenticator = builder.authenticator;
    this.connectionPool = builder.connectionPool;
    this.dns = builder.dns;
    this.followSslRedirects = builder.followSslRedirects;
    this.followRedirects = builder.followRedirects;
    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
    this.connectTimeout = builder.connectTimeout;
    this.readTimeout = builder.readTimeout;
    this.writeTimeout = builder.writeTimeout;
    this.pingInterval = builder.pingInterval;

    if (interceptors.contains(null)) {
      throw new IllegalStateException("Null interceptor: " + interceptors);
    }
    if (networkInterceptors.contains(null)) {
      throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
    }
  }

new OkHttpClient() 通过构造直接创建OkHttpClient实例

// 直接调用 this(new Builder());方法
 public OkHttpClient() {
    this(new Builder());
  }

 跟进this(new Builder());

 调用了含参构造方法 OkHttpClient(Builder builder) {,同时使用匿名创建Builder对象实例

 继续查看new Builder()
  public Builder() {
 通过调用查看类似于使用

 new OkHttpClient.Builder().build()方法

client.newBuilder()

 public Builder newBuilder() {
    return new Builder(this);
  }

查看调用,内部调用了Builder的含参构造方法将okHttpClient作为参数传递
Builder(OkHttpClient okHttpClient) {

继续跟进 new Builder(this);

    Builder(OkHttpClient okHttpClient) {
      this.dispatcher = okHttpClient.dispatcher;
      // 代理
      this.proxy = okHttpClient.proxy;
      this.protocols = okHttpClient.protocols;
      this.connectionSpecs = okHttpClient.connectionSpecs;
      // 拦截器
      this.interceptors.addAll(okHttpClient.interceptors);
      // 网络拦截器
      this.networkInterceptors.addAll(okHttpClient.networkInterceptors);
      this.eventListenerFactory = okHttpClient.eventListenerFactory;
      this.proxySelector = okHttpClient.proxySelector;
      this.cookieJar = okHttpClient.cookieJar;
      // 内部缓存
      this.internalCache = okHttpClient.internalCache;
      // 缓存
      this.cache = okHttpClient.cache;
      this.socketFactory = okHttpClient.socketFactory;
      // ssl Scoket工厂
      this.sslSocketFactory = okHttpClient.sslSocketFactory;
      // 认证链cleaner
      this.certificateChainCleaner = okHttpClient.certificateChainCleaner;
      this.hostnameVerifier = okHttpClient.hostnameVerifier;
      this.certificatePinner = okHttpClient.certificatePinner;
      this.proxyAuthenticator = okHttpClient.proxyAuthenticator;
      this.authenticator = okHttpClient.authenticator;
      // 连接池
      this.connectionPool = okHttpClient.connectionPool;
      this.dns = okHttpClient.dns;
      this.followSslRedirects = okHttpClient.followSslRedirects;
      this.followRedirects = okHttpClient.followRedirects;
      this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure;
      this.connectTimeout = okHttpClient.connectTimeout;
      this.readTimeout = okHttpClient.readTimeout;
      this.writeTimeout = okHttpClient.writeTimeout;
      this.pingInterval = okHttpClient.pingInterval;
    }

通过查看Builder构造方法,对比无参构造方法,新增了缓存、拦截器赋值操作,实现共享client的相同的连接池、线程池和参数配置

readTimeout(500, TimeUnit.MILLISECONDS)

// 设置读取新连接超时时间
 public Builder readTimeout(long timeout, TimeUnit unit) {
      readTimeout = checkDuration("timeout", timeout, unit);
      return this;
    }

.build();

build方法与使用okHttpClient.Buider()方式的build相同,通过构造OkHttpClient

 public OkHttpClient build() {
      return new OkHttpClient(this);
    }

okHttpClient.newCall(request).execute();

  /**
   * Prepares the {@code request} to be executed at some point in the future.
   */
   // 准备在未来的某个点执行请求操作
  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }


  继续跟进 RealCall.newRealCall(this, request, false /* for web socket */);

   static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    // 安全的发布一个call实例到EventListener
    // 创建realCall实例
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    // 创建eventListener监听
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
  }


  // 查看new RealCall(client, originalRequest, forWebSocket)调用
  // 其实就是通过构造传参
   private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

  查看client.eventListenerFactory().create(call)实现,通过传递的call实例创建EventListener

   public interface Factory {
    /**
     * Creates an instance of the {@link EventListener} for a particular {@link Call}. The returned
     * {@link EventListener} instance will be used during the lifecycle of the {@code call}.
     *
     * <p>This method is invoked after the {@code call} is created. See
     * {@link OkHttpClient#newCall(Request)}.
     *
     * <p><strong>It is an error for implementations to issue any mutating operations on the
     * {@code call} instance from this method.</strong>
     */
    EventListener create(Call call);
  }

execute();

public interface Call extends Cloneable {’

 Response execute() throws IOException;
 通过查看call是一个接口类型,我们要具体execute方法要查看其实现类也就是RealCall中execute()方法

 RealCall中execute()方法

  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      // execute标记
      executed = true;
    }
    // 捕获调用堆栈跟踪
    captureCallStackTrace();
    // callStart监听
    eventListener.callStart(this);
    try {
    // 调用okHttpClient的dispatch执行操作
      client.dispatcher().executed(this);
      // 通过拦截器链获取响应
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
    // 回调callFailed方法
      eventListener.callFailed(this, e);
      throw e;
    } finally {
    // 结束okHttpClinet的diapatcher分发
      client.dispatcher().finished(this);
    }
  }


 查看getResponseWithInterceptorChain()实现

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    // 添加拦截器
    interceptors.addAll(client.interceptors());
    // 添加重试和追踪拦截器
    interceptors.add(retryAndFollowUpInterceptor);
    // 添加BridgeInterceptor
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    // 添加CacheInterceptor
    interceptors.add(new CacheInterceptor(client.internalCache()));
    // 添加ConnectInterceptor
    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());
    // 通过chain的process方法获取response
    return chain.proceed(originalRequest);
  }


  查看chain.proceed(originalRequest)实现
   @Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }

  继续查看proceed方法实现

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

    calls++;

   // 省略部分代码

    // Call the next interceptor in the chain.
    // 创建真正的拦截器链
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
        // 根据索引获取interceptor拦截器
    Interceptor interceptor = interceptors.get(index);
    // 通过拦截器获取响应数据
    Response response = interceptor.intercept(next);

   // 省略部分代码
    return response;
  }

  // 继续查看 interceptor.intercept(next)方法实现

  public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

Interceptor 拦截器

BridgeInterceptor 桥梁拦截器

应用代码到网络代码的桥梁,从用户请求创建网络请求,进行网络访问,最后从网络响应购将用户响应,主要用于处理header

/**
 * Bridges from application code to network code. First it builds a network request from a user
 * request. Then it proceeds to call the network. Finally it builds a user response from the network
 * response.
 */
public final class BridgeInterceptor implements Interceptor {
  private final CookieJar cookieJar;

  public BridgeInterceptor(CookieJar cookieJar) {
    this.cookieJar = cookieJar;
  }

  @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) {
      // 添加header
        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");
    }
    // 从request强求中获取cookie
    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
    // 添加cookie header
      requestBuilder.header("Cookie", cookieHeader(cookies));
    }

    if (userRequest.header("User-Agent") == null) {
    // 添加version到header 
      requestBuilder.header("User-Agent", Version.userAgent());
    }
    // 获取响应response
    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)));
    }
    // 返回为header赋值后的responseBuilder
    return responseBuilder.build();
  }

  /** Returns a 'Cookie' HTTP request header with all cookies, like {@code a=b; c=d}. */
  // 添加CookieHeader
  private String cookieHeader(List<Cookie> cookies) {
    StringBuilder cookieHeader = new StringBuilder();
    for (int i = 0, size = cookies.size(); i < size; i++) {
      if (i > 0) {
        cookieHeader.append("; ");
      }
      Cookie cookie = cookies.get(i);
      cookieHeader.append(cookie.name()).append('=').append(cookie.value());
    }
    return cookieHeader.toString();
  }
}

CacheInterceptor 缓存拦截器

/** Serves requests from the cache and writes responses to the cache. */
// 服务器从缓存中请求并且将响应写入缓存中

public final class CacheInterceptor implements Interceptor {
    // 内部缓存
  final InternalCache cache;

  public CacheInterceptor(InternalCache cache) {
    this.cache = cache;
  }

  @Override public Response intercept(Chain chain) throws IOException {
  // 存在缓存,从缓存中获取,不存在缓存为null
    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) {
    //跟踪http响应
      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.
    //禁止使用网络或者缓存不足,失败
    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.
    // 没有网络,读取缓存
    if (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }

    Response networkResponse = null;
    try {
    // 通过拦截器获取网络响应
      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.
    // 缓存不为空,并且响应没有发生改变
    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;
  }

  private static Response stripBody(Response response) {
    return response != null && response.body() != null
        ? response.newBuilder().body(null).build()
        : response;
  }

  /**
   * Returns a new source that writes bytes to {@code cacheRequest} as they are read by the source
   * consumer. This is careful to discard bytes left over when the stream is closed; otherwise we
   * may never exhaust the source stream and therefore not complete the cached response.
   */
   // 缓存写入响应
  private Response cacheWritingResponse(final CacheRequest cacheRequest, Response response)
      throws IOException {
    // Some apps return a null body; for compatibility we treat that like a null cache request.
    if (cacheRequest == null) return response;
    Sink cacheBodyUnbuffered = cacheRequest.body();
    if (cacheBodyUnbuffered == null) return response;

    final BufferedSource source = response.body().source();
    final BufferedSink cacheBody = Okio.buffer(cacheBodyUnbuffered);

    Source cacheWritingSource = new Source() {
      boolean cacheRequestClosed;

      @Override public long read(Buffer sink, long byteCount) throws IOException {
        long bytesRead;
        try {
          bytesRead = source.read(sink, byteCount);
        } catch (IOException e) {
          if (!cacheRequestClosed) {
            cacheRequestClosed = true;
            cacheRequest.abort(); // Failed to write a complete cache response.
          }
          throw e;
        }

        if (bytesRead == -1) {
          if (!cacheRequestClosed) {
            cacheRequestClosed = true;
            cacheBody.close(); // The cache response is complete!
          }
          return -1;
        }

        sink.copyTo(cacheBody.buffer(), sink.size() - bytesRead, bytesRead);
        cacheBody.emitCompleteSegments();
        return bytesRead;
      }

      @Override public Timeout timeout() {
        return source.timeout();
      }

      @Override public void close() throws IOException {
        if (!cacheRequestClosed
            && !discard(this, HttpCodec.DISCARD_STREAM_TIMEOUT_MILLIS, MILLISECONDS)) {
          cacheRequestClosed = true;
          cacheRequest.abort();
        }
        source.close();
      }
    };

    String contentType = response.header("Content-Type");
    long contentLength = response.body().contentLength();
    return response.newBuilder()
        .body(new RealResponseBody(contentType, contentLength, Okio.buffer(cacheWritingSource)))
        .build();
  }

  /** Combines cached headers with a network headers as defined by RFC 7234, 4.3.4. */
  // 合并headers
  private static Headers combine(Headers cachedHeaders, Headers networkHeaders) {
    Headers.Builder result = new Headers.Builder();

    for (int i = 0, size = cachedHeaders.size(); i < size; i++) {
      String fieldName = cachedHeaders.name(i);
      String value = cachedHeaders.value(i);
      if ("Warning".equalsIgnoreCase(fieldName) && value.startsWith("1")) {
        continue; // Drop 100-level freshness warnings.
      }
      if (isContentSpecificHeader(fieldName) || !isEndToEnd(fieldName)
              || networkHeaders.get(fieldName) == null) {
        Internal.instance.addLenient(result, fieldName, value);
      }
    }
    // 遍历networkHeaders
    for (int i = 0, size = networkHeaders.size(); i < size; i++) {
      String fieldName = networkHeaders.name(i);
      if (!isContentSpecificHeader(fieldName) && isEndToEnd(fieldName)) {
        Internal.instance.addLenient(result, fieldName, networkHeaders.value(i));
      }
    }

    return result.build();
  }

  /**
   * Returns true if {@code fieldName} is an end-to-end HTTP header, as defined by RFC 2616,
   * 13.5.1.
   */
  static boolean isEndToEnd(String fieldName) {
    return !"Connection".equalsIgnoreCase(fieldName)
        && !"Keep-Alive".equalsIgnoreCase(fieldName)
        && !"Proxy-Authenticate".equalsIgnoreCase(fieldName)
        && !"Proxy-Authorization".equalsIgnoreCase(fieldName)
        && !"TE".equalsIgnoreCase(fieldName)
        && !"Trailers".equalsIgnoreCase(fieldName)
        && !"Transfer-Encoding".equalsIgnoreCase(fieldName)
        && !"Upgrade".equalsIgnoreCase(fieldName);
  }

  /**
   * Returns true if {@code fieldName} is content specific and therefore should always be used
   * from cached headers.
   */
  static boolean isContentSpecificHeader(String fieldName) {
    return "Content-Length".equalsIgnoreCase(fieldName)
        || "Content-Encoding".equalsIgnoreCase(fieldName)
        || "Content-Type".equalsIgnoreCase(fieldName);
  }
}

RetryAndFollowUpInterceptor 重试和重定向拦截器

主要代码

  @Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Call call = realChain.call();
    EventListener eventListener = realChain.eventListener();

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

    int followUpCount = 0;
    Response priorResponse = null;
    while (true) {
      if (canceled) {
        streamAllocation.release();
        throw new IOException("Canceled");
      }

      Response response;
      boolean releaseConnection = true;
      try {
      // 获取响应数据
        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.
        // RouteException 路径异常,尝试恢复
        if (!recover(e.getLastConnectException(), streamAllocation, 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, streamAllocation, 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.
      if (priorResponse != null) {
        response = response.newBuilder()
            .priorResponse(priorResponse.newBuilder()
                    .body(null)
                    .build())
            .build();
      }
    // 重定向
      Request followUp = followUpRequest(response, streamAllocation.route());

      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);
        this.streamAllocation = streamAllocation;
      } 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;
    }
  }

ConnectInterceptor 连接拦截器

/** Opens a connection to the target server and proceeds to the next interceptor. */
//向目标服务器开启一个连接,并传递给下一个拦截器
public final class ConnectInterceptor implements Interceptor {
  public final OkHttpClient client;

  public ConnectInterceptor(OkHttpClient client) {
    this.client = client;
  }

  @Override public Response intercept(Chain chain) throws IOException {
  // 强转为RealInterceptorChain
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    // 获取request对象
    Request request = realChain.request();
    // 通过realChain获取streamAllocation(流分配)
    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 httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    //使用streamAllocation进行链接
    RealConnection connection = streamAllocation.connection();
    // proceed
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }
}

这个拦截器中使用的多个其他类对象,重点代码进行分析

   HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);

查看该方法源码:

 public HttpCodec newStream(
      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();

    try {
    // 寻找健康的链接,其实可以理解为查询有效链接
      RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
          writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
      HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);

      synchronized (connectionPool) {
        codec = resultCodec;
        return resultCodec;
      }
    } catch (IOException e) {
      throw new RouteException(e);
    }
  }

 继续查看findHealthyConnection

  /**
   * Finds a connection and returns it if it is healthy. If it is unhealthy the process is repeated
   * until a healthy connection is found.
   */
   // 寻找一个链接并返回是否健康,如果不健康就重复处理,直到找到健康的连接为止

  private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
      int writeTimeout, int pingIntervalMillis, boolean connectionRetryEnabled,
      boolean doExtensiveHealthChecks) throws IOException {
      // 死循环
    while (true) {
      RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
          pingIntervalMillis, connectionRetryEnabled);

      // If this is a brand new connection, we can skip the extensive health checks.
      // 如果是一个新的连接,跳过检查,直接返回作为健康的连接
      synchronized (connectionPool) {
        if (candidate.successCount == 0) {
          return candidate;
        }
      }

      // Do a (potentially slow) check to confirm that the pooled connection is still good. If it
      // isn't, take it out of the pool and start again.
      // 不健康的连接从池子中移除,继续寻找
      if (!candidate.isHealthy(doExtensiveHealthChecks)) {
        noNewStreams();
        continue;
      }

      return candidate;
    }
  }

继续查看findConnection

/**
   * Returns a connection to host a new stream. This prefers the existing connection if it exists,
   * then the pool, finally building a new connection.
   */
   // 返回连接到host的新的流,优先选择存在的在池中的连接,最后创建一个新的连接
  private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
      int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
    boolean foundPooledConnection = false;
    RealConnection result = null;
    Route selectedRoute = null;
    Connection releasedConnection;
    Socket toClose;
    synchronized (connectionPool) {
      if (released) throw new IllegalStateException("released");
      if (codec != null) throw new IllegalStateException("codec != null");
      if (canceled) throw new IOException("Canceled");

      // Attempt to use an already-allocated connection. We need to be careful here because our
      // already-allocated connection may have been restricted from creating new streams.
      // 当前连接作为释放的连接
      releasedConnection = this.connection;
      // 如果没有新的流释放连接
      toClose = releaseIfNoNewStreams();
      if (this.connection != null) {
        // We had an already-allocated connection and it's good.
        // 已经分配了连接,并且是好的,就把当前连接作为结果返回
        result = this.connection;
        releasedConnection = null;
      }
      if (!reportedAcquired) {
        // If the connection was never reported acquired, don't report it as released!
        releasedConnection = null;
      }

    // result为空,尝试从连接池中获取
      if (result == null) {
        // Attempt to get a connection from the pool.
        Internal.instance.get(connectionPool, address, this, null);
        if (connection != null) {
        // 找到了连接就对result进行赋值
          foundPooledConnection = true;
          result = connection;
        } else {
          selectedRoute = route;
        }
      }
    }
    closeQuietly(toClose);

    if (releasedConnection != null) {
      eventListener.connectionReleased(call, releasedConnection);
    }
    if (foundPooledConnection) {
      eventListener.connectionAcquired(call, result);
    }
    if (result != null) {
    // result不为空,直接返回
      // If we found an already-allocated or pooled connection, we're done.
      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();
    }

    synchronized (connectionPool) {
      if (canceled) throw new IOException("Canceled");

      if (newRouteSelection) {
        // Now that we have a set of IP addresses, make another attempt at getting a connection from
        // the pool. This could match due to connection coalescing.
        // 现在我们拥有了IP地址集合,尝试从池子中获取一个连接
        List<Route> routes = routeSelection.getAll();
        for (int i = 0, size = routes.size(); i < size; i++) {
          Route route = routes.get(i);
          Internal.instance.get(connectionPool, address, this, route);
          if (connection != null) {
            foundPooledConnection = true;
            result = connection;
            this.route = route;
            break;
          }
        }
      }
        //没找到连接,创建一个新的并立即分配
      if (!foundPooledConnection) {
        if (selectedRoute == null) {
          selectedRoute = routeSelection.next();
        }

        // Create a connection and assign it to this allocation immediately. This makes it possible
        // for an asynchronous cancel() to interrupt the handshake we're about to do.
        route = selectedRoute;
        refusedStreamCount = 0;
        result = new RealConnection(connectionPool, selectedRoute);
       // 把当前的连接添加到connection.allocations中
        acquire(result, false);
      }
    }

    // If we found a pooled connection on the 2nd time around, we're done.
    // 如果第二次从池中找到连接,就可以了,直接将result返回
    if (foundPooledConnection) {
      eventListener.connectionAcquired(call, result);
      return result;
    }

    // Do TCP + TLS handshakes. This is a blocking operation.
    // 进行连接
    result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
        connectionRetryEnabled, call, eventListener);
    routeDatabase().connected(result.route());
    Socket socket = null;
    synchronized (connectionPool) {
      reportedAcquired = true;

      // Pool the connection.
      // 将连接放到连接池中
      Internal.instance.put(connectionPool, result);

      // If another multiplexed connection to the same address was created concurrently, then
      // release this connection and acquire that one.
      // 如果另外一个多路连接连接到相同的地址,释放当前这个,并且接受新的那个
      // 重复连接进行替换
      if (result.isMultiplexed()) {
        socket = Internal.instance.deduplicate(connectionPool, address, this);
        result = connection;
      }
    }
    closeQuietly(socket);

    eventListener.connectionAcquired(call, result);
    return result;
  }


看完了findConnection继续查看noNewStreams();

  /** Forbid new streams from being created on the connection that hosts this allocation. */
  // 阻止从已分配的host创建新的stream

  public void noNewStreams() {
    Socket socket;
    Connection releasedConnection;
    synchronized (connectionPool) {
      releasedConnection = connection;
      // 释放
      socket = deallocate(true, false, false);
      if (connection != null) releasedConnection = null;
    }
    // 安全关闭socket
    closeQuietly(socket);
    if (releasedConnection != null) {
      eventListener.connectionReleased(call, releasedConnection);
    }
  }

  继续查看deallocate

  /**
   * Releases resources held by this allocation. If sufficient resources are allocated, the
   * connection will be detached or closed. Callers must be synchronized on the connection pool.
   *
   * <p>Returns a closeable that the caller should pass to {@link Util#closeQuietly} upon completion
   * of the synchronized block. (We don't do I/O while synchronized on the connection pool.)
   */

  private Socket deallocate(boolean noNewStreams, boolean released, boolean streamFinished) {
    assert (Thread.holdsLock(connectionPool));

    if (streamFinished) {
      this.codec = null;
    }
    if (released) {
      this.released = true;
    }
    Socket socket = null;
    if (connection != null) {
      if (noNewStreams) {
      // 如果没有新的流的时候,不创建新的连接
        connection.noNewStreams = true;
      }
      if (this.codec == null && (this.released || connection.noNewStreams)) {
      // 释放连接
        release(connection);
        if (connection.allocations.isEmpty()) {
          connection.idleAtNanos = System.nanoTime();
          if (Internal.instance.connectionBecameIdle(connectionPool, connection)) {
            socket = connection.socket();
          }
        }
        connection = null;
      }
    }
    return socket;
  }

CallServerInterceptor call服务器拦截器

/** This is the last interceptor in the chain. It makes a network call to the server. */
最后一个拦截器,使网络连接到服务器
public final class CallServerInterceptor implements Interceptor {

  @Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    // 通过httpStream获取httpCode对象
    HttpCodec httpCodec = realChain.httpStream();
    StreamAllocation streamAllocation = realChain.streamAllocation();
    RealConnection connection = (RealConnection) realChain.connection();
    // 通过realChain获取request对象
    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();
    // 响应Builder为空则httpCodec不再读取响应头
    if (responseBuilder == null) {
      realChain.eventListener().responseHeadersStart(realChain.call());
      responseBuilder = httpCodec.readResponseHeaders(false);
    }

    // 通过responseBuilder构建response实例
    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    int code = response.code();
    // code为100,重新尝试读取实际响应
    if (code == 100) {
      // server sent a 100-continue even though we did not request one.
      // try again to read the actual response
      responseBuilder = httpCodec.readResponseHeaders(false);

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

      code = response.code();
    }

    realChain.eventListener()
            .responseHeadersEnd(realChain.call(), 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(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;
  }


最后还有一个HttpCodec

/** Encodes HTTP requests and decodes HTTP responses. */
用于加密HTTP请求和解密HTTP响应
public interface HttpCodec {
ConnectionPool
/**
 * Manages reuse of HTTP and HTTP/2 connections for reduced network latency. HTTP requests that
 * share the same {@link Address} may share a {@link Connection}. This class implements the policy
 * of which connections to keep open for future use.
 */
 // 管理http和http2连接的复用来减少网络延迟,具有相同地址的http请求共享连接,实现了连接保持开启策略,用于将来使用
public final class ConnectionPool {
/**
   * Create a new connection pool with tuning parameters appropriate for a single-user application.
   * The tuning parameters in this pool are subject to change in future OkHttp releases. Currently
   * this pool holds up to 5 idle connections which will be evicted after 5 minutes of inactivity.
   */
   // 初始拥有5个空闲连接,不活动的连接5分钟后将会被移除
 public ConnectionPool() {
    this(5, 5, TimeUnit.MINUTES);
  }

主要方法 

get() 获取

// 返回一个回收连接,如果该连接不存在返回null,如果地址没有被路由分配链路为空
  /**
   * Returns a recycled connection to {@code address}, or null if no such connection exists. The
   * route is null if the address has not yet been routed.
   */
  @Nullable RealConnection get(Address address, StreamAllocation streamAllocation, Route route) {
    assert (Thread.holdsLock(this));
    for (RealConnection connection : connections) {
    // 判断连接是否携带流分配到地址
      if (connection.isEligible(address, route)) {
      // 将当前连接添加到streamAllocation中
        streamAllocation.acquire(connection, true);
        return connection;
      }
    }
    return null;
  }

deduplicate() 对于重复的连接进行替换,类似hashmap键重复,值覆盖

  /**
   * Replaces the connection held by {@code streamAllocation} with a shared connection if possible.
   * This recovers when multiple multiplexed connections are created concurrently.
   */
  @Nullable Socket deduplicate(Address address, StreamAllocation streamAllocation) {
    assert (Thread.holdsLock(this));
    for (RealConnection connection : connections) {
      if (connection.isEligible(address, null)
          && connection.isMultiplexed()
          && connection != streamAllocation.connection()) {
        return streamAllocation.releaseAndAcquire(connection);
      }
    }
    return null;
  }

put() 添加

  void put(RealConnection connection) {
    assert (Thread.holdsLock(this));
    if (!cleanupRunning) {
      cleanupRunning = true;
      executor.execute(cleanupRunnable);
    }
    // 向连接池中添加连接
    connections.add(connection);
  }

evictAll() 清空

  /** Close and remove all idle connections in the pool. */
  // 从池中关闭并移除所有空闲的连接
  public void evictAll() {
    List<RealConnection> evictedConnections = new ArrayList<>();
    synchronized (this) {
      for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) {
        RealConnection connection = i.next();
        if (connection.allocations.isEmpty()) {
          connection.noNewStreams = true;
          evictedConnections.add(connection);
          i.remove();
        }
      }
    }

    for (RealConnection connection : evictedConnections) {
      closeQuietly(connection.socket());
    }
  }

call.cancel(); 取消call,取消请求

查看RealCall的cancel方法

 @Override public void cancel() {
    retryAndFollowUpInterceptor.cancel();
  }


 继续跟进RetryAndFollowUpInterceptor的cancel方法

   /**
   * Immediately closes the socket connection if it's currently held. Use this to interrupt an
   * in-flight request from any thread. It's the caller's responsibility to close the request body
   * and response body streams; otherwise resources may be leaked.
   *
   * <p>This method is safe to be called concurrently, but provides limited guarantees. If a
   * transport layer connection has been established (such as a HTTP/2 stream) that is terminated.
   * Otherwise if a socket connection is being established, that is terminated.
   */

   // 立即关闭socket连接,立即关闭任何线程动态的请求,该调用用来关闭响应体和响应体流数据,然而资源可能泄露。
   // 回调是安全的,并且提供了有效的担保
   // 如果传输层已经进入开启状态,会被终止
  public void cancel() {
    canceled = true;
    StreamAllocation streamAllocation = this.streamAllocation;
    if (streamAllocation != null) streamAllocation.cancel();
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值