OkHttp3源码解析--OkHttpClient和Request创建过程

OkHttp3的分析过程将以以下代码调用过程进行:

//步骤1:创建OkHttpClient对象
OkHttpClient client = new OkHttpClient.Builder()
  .readTimeout(5, TimeUnit.SECONDS)
  .build();
//步骤2:创建Request对象
Request request = new Request.Builder()
    .url("http://www.baidu.com")
    .get()
    .build();
//步骤3:创建Call对象
Call call = client.newCall(request);
//步骤4:进行请求
//异步请求方式
call.enqueue(new Callback() {
  @Override
  public void onFailure(Call call, IOException e) {
    System.out.println("Fail");
  }
  @Override
  public void onResponse(Call call, Response response) throws IOException {
    System.out.println(response.body().string());
  }
});
//同步请求方式
Response response = call.execute();

OkHttpClient创建

OkHttpClient创建过程是一个构建者模式应用的过程,OkHttpClient类有个静态内部类Builder

public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
    final Dispatcher dispatcher;//请求分发器,负责将请求任务保存至队列,并分发到某个空闲线程,接着执行,执行完关闭任务。
    final @Nullable Proxy proxy;//代理
    final List<Protocol> protocols;//默认支持的协议,如Protocol.HTTP_2, Protocol.HTTP_1_1
    final List<ConnectionSpec> connectionSpecs;//连接Connection的参数配置,如加密认证的TLS连接,普通未加密未认证的连接等
    final List<Interceptor> interceptors;//请求过程中的拦截器,包括连接建立之前和之后的所有拦截器
    final List<Interceptor> networkInterceptors;//网络拦截器
    final EventListener.Factory eventListenerFactory;//请求状态监听
    final ProxySelector proxySelector;//代理选择器
    final CookieJar cookieJar;//默认是没有Cookie的
    final @Nullable Cache cache;//缓存
    final @Nullable InternalCache internalCache;//内部缓存
    final SocketFactory socketFactory;//创建Socket的工厂
    final @Nullable SSLSocketFactory sslSocketFactory;//创建加密认证Socket的工厂
    final @Nullable CertificateChainCleaner certificateChainCleaner;//安全相关配置
    final HostnameVerifier hostnameVerifier;//安全相关配置
    final CertificatePinner certificatePinner;//安全相关配置
    final Authenticator proxyAuthenticator;//安全相关配置
    final Authenticator authenticator;//安全相关配置
    final ConnectionPool connectionPool;//连接池
    final Dns dns;//域名解析系统 domain name -> ip address
    final boolean followSslRedirects;//在加密认证的情况下,是否支持重定向
    final boolean followRedirects;//是否支持重定向
    final boolean retryOnConnectionFailure;//连接失败时,是否重试
    final int connectTimeout;//连接超时时间
    final int readTimeout;//读取响应超时时间
    final int writeTimeout;//写入请求超时时间
    final int pingInterval;//WebSocket相关,为了保持长连接,使用Ping命令维持连接。
    //构造者模式
    public static final class Builder {
        Dispatcher dispatcher;
        @Nullable Proxy proxy;
        List<Protocol> protocols;
        List<ConnectionSpec> connectionSpecs;
        final List<Interceptor> interceptors = new ArrayList<>();
        final List<Interceptor> networkInterceptors = new ArrayList<>();
        EventListener.Factory eventListenerFactory;
        ProxySelector proxySelector;
        CookieJar cookieJar;
        @Nullable Cache cache;
        @Nullable InternalCache internalCache;
        SocketFactory socketFactory;
        @Nullable SSLSocketFactory sslSocketFactory;
        @Nullable CertificateChainCleaner certificateChainCleaner;
        HostnameVerifier hostnameVerifier;
        CertificatePinner certificatePinner;
        Authenticator proxyAuthenticator;
        Authenticator authenticator;
        ConnectionPool connectionPool;
        Dns dns;
        boolean followSslRedirects;
        boolean followRedirects;
        boolean retryOnConnectionFailure;
        int connectTimeout;
        int readTimeout;
        int writeTimeout;
        int pingInterval;
        //初始化
        public Builder() {
          dispatcher = new Dispatcher();//直接new了一个对象
          protocols = DEFAULT_PROTOCOLS;//默认的协议
          connectionSpecs = DEFAULT_CONNECTION_SPECS;//默认的连接规格
          eventListenerFactory = EventListener.factory(EventListener.NONE);
          proxySelector = ProxySelector.getDefault();
          cookieJar = CookieJar.NO_COOKIES;//默认无cookies
          socketFactory = SocketFactory.getDefault();//默认的SocketFactory
          hostnameVerifier = OkHostnameVerifier.INSTANCE;
          certificatePinner = CertificatePinner.DEFAULT;
          proxyAuthenticator = Authenticator.NONE;
          authenticator = Authenticator.NONE;
          connectionPool = new ConnectionPool();//直接new一个连接池对象,
          dns = Dns.SYSTEM;
          followSslRedirects = true;
          followRedirects = true;//默认可以重定向
          retryOnConnectionFailure = true;//默认连接失败后,自动重试
          connectTimeout = 10_000;//连接超时
          readTimeout = 10_000;//读超时
          writeTimeout = 10_000;//写超时
          pingInterval = 0;
        }
}

一些重要的成员变量的解析:

  • Dispatcher:负责维护请求队列,分发请求至连接池,执行请求,结束请求,并进行任务执行的调度,执行下一个请求;

  • ConnectionSpec:Socket连接的规格属性,内部通过构建者模式进行对象的创建,看源码中的两个例子:

static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(
      ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT);
/** A modern TLS connection with extensions like SNI and ALPN available. */
//有加密和认证的连接
public static final ConnectionSpec MODERN_TLS = new Builder(true)
  .cipherSuites(APPROVED_CIPHER_SUITES)
  .tlsVersions(TlsVersion.TLS_1_3, TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
  .supportsTlsExtensions(true)
  .build();/** Unencrypted, unauthenticated connections for {@code http:} URLs. */
//无加密和认证的连接
public static final ConnectionSpec CLEARTEXT = new Builder(false).build();
  • Interceptor:拦截器,OkHttp在后续处理请求的时候,应用了牛逼的拦截器链模式。其中有失败重试/重定向拦截器,桥接拦截器,缓存拦截器,连接建立拦截器,网络请求拦截器。用户也可以自定义拦截器,用户自定义的拦截器会放在拦截器链的开始位置,最先执行。

  • ConnectionPool:Socket连接池,在建立连接时可以在连接池中查找是否有可用的连接。在初始化的时候,new ConnectionPool()的时候:

public ConnectionPool() {
    this(5, 5, TimeUnit.MINUTES);
}
//maxIdleConnections:最多可空闲的连接数量
//keepAliveDuration:保活时间;TimeUnit前面保活时间的时间单位
//源码中默认是:连接池中最多可有5个空闲的连接,并且,这5个连接如果在5分钟内一直空闲,将被移除连接池,即关闭。
public ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
  this.maxIdleConnections = maxIdleConnections;
  this.keepAliveDurationNs = timeUnit.toNanos(keepAliveDuration);
  // Put a floor on the keep alive duration, otherwise cleanup will spin loop.
  if (keepAliveDuration <= 0) {
    throw new IllegalArgumentException("keepAliveDuration <= 0: " + keepAliveDuration);
  }
}

最后OkHttpClient中的内部类中Builder的build方法完成OkHttpClient的创建工作:

public OkHttpClient build() {
   return new OkHttpClient(this);
}//调用这个构造方法
//全是引用传递,因为具体的初始化过程,已经在Builder中完成了
OkHttpClient(Builder builder) {
    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) {
      this.sslSocketFactory = builder.sslSocketFactory;
      this.certificateChainCleaner = builder.certificateChainCleaner;
    } else {
      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);
    }
  }

设计模式简析

整体来看,OkhttpClient的创建过程是一个非常典型的构造者模式的应用,同时也是一个外观模式的应用,我们应用者仅仅通过非常简短的代码调用,即可完成非常复杂的初始化过程;

构造者模式应用时机:在非常复杂的对象创建的过程中;这样可以防止必须提供多个构造器。如上面的OkhttpClient类中有多个成员属性变量,但是在创建对象的时候我们根据不同的需求,可能需要使用其中不同组合的成员属性,这个时候如果不实用构造者模式,就需要提供多个构造器。而使用构造者模式,我们就可以非常灵活的初始化OkhttpClient,无论它使用什么样的成员变量组合。

再看一下Request的创建过程,同样,它也是一个非常典型的构造者模式的应用。

Request创建过程

public final class Request {
  final HttpUrl url;//请求的URL
  final String method;//请求方法,post  get
  final Headers headers;//请求头部
  final @Nullable RequestBody body;//请求内容
  final Object tag;//在取消这个请求是时候会用到
  private volatile CacheControl cacheControl; // Lazily initialized.
  
  Request(Builder builder) {
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tag = builder.tag != null ? builder.tag : this;
  }
  
  public static class Builder {
    HttpUrl url;
    String method;
    Headers.Builder headers;
    RequestBody body;
    Object tag;
    
    public Builder() {
      this.method = "GET";//请求方法默认是GET方法
      this.headers = new Headers.Builder();
    }
    public Builder url(HttpUrl url) {
      if (url == null) throw new NullPointerException("url == null");
      this.url = url;
      return this;
    }
    
    public Builder url(String url) {
      if (url == null) throw new NullPointerException("url == null");// Silently replace web socket URLs with HTTP URLs.
      if (url.regionMatches(true, 0, "ws:", 0, 3)) {
        url = "http:" + url.substring(3);
      } else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
        url = "https:" + url.substring(4);
      }
​
      HttpUrl parsed = HttpUrl.parse(url);
      if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);
      return url(parsed);
    }
  }
  
  public Builder addHeader(String name, String value) {
      headers.add(name, value);
      return this;
    }
  
  public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);//转到Request构造其中,同样的味道,同样的料
    }
}

通过上述两个过程,创建了OkHttpClient和Request两个对象。

OkHttpClient比喻成一辆车,Request就好比我们要去的目的地,现在已经确定了目的地,接下来就是路途上会发生哪些事情了。

你可能感兴趣的:(okhttp,okhttp)