前言
在上一篇文章《OkHttp总体框架介绍》中,我简单的介绍了一下我对OkHttp总体架构设计的一个理解,在文章中,我对OkHttp的各个层次和各个关键的类都做了一个简单的介绍。那这一章节开始,我就开始从更加详细的角度去分析这些关键类的源码,那首当其冲的就是OkHttpClient。
OkHttpClient可以看作是OKHTTP的一个全局应用上下文,在一个应用中往往只会创建一个单例。它主要有两个功能
- 可配置、存储和获取一些全局的属性配置,比如超时时间、自定义的CookieJar实现、自定义的Interceptor实现、添加事件监听等等。
- 负责创建和管理一些全局单例对象,比如Dispatcher、ConnectionPool等。
- 提供newCall API,我们用的最多也是这个API,例如
String respJson = okHttpClient.newCall(request).execute().body().string();
OKhttpClient中大部分的代码都是其属性的配置,并没有什么逻辑上的实现,所以下面我们就从其各个属性开始,去逐步了解OKhttpClient的源码。
属性
对于OkHttp的属性,我主要根据其特性和层次对其进行分类。但是这里不会出现上一篇文章架构图中描绘的所有类,因为那图中的类或者接口不是所有都对外开放的,一些是内部使用的API,例如:Transmitter、Exchange、Connection这些都不会出现在OKHttpClient中。
基础配置
这些属性主要是一些全局性的基础配置,它们中大部分都是对用户开放的,可获取可设置。它们会存储在OkHttp实例当中,并且会在全局范围内被各个层次的模块使用,主要是用来控制通信的一些基本行为,比如请求超时时间,是否SSL重定向,是否Http重定向,是否使用缓存、支持的协议等。
//协议簇-只支持HTTP_2/HTTP_1_1,并且不可修改
static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList(Protocol.HTTP_2/, Protocol.HTTP_1_1);
//默认连接规范
//ConnectionSpec.CLEARTEXT:Http的规范配置
//ConnectionSpec.MODERN_TLS:TLS规范配置
static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(ConnectionSpec.MODERN_TLS,ConnectionSpec.CLEARTEXT);
//是否SSL重定向
final boolean followSslRedirects;
//是否http重定向
final boolean followRedirects;
//请求超时(connect + write + read)默认没限制
final int callTimeout;
//连接超时(对应tcp connect())
final int connectTimeout;
//读取超时(对应TCP read())默认10s
final int readTimeout;
//写入超时(对应TCP write())默认10s
final int pingInterval;
//ping周期
final int writeTimeout;
线程资源管理层
这一层次的类只有Dispatcher一个。
final Dispatcher dispatcher;
OkHttpClient.Buider会使用其的无参构造函数创建一个默认的实现,无参构造函数会使用内置的线程池来执行异步任务。
public Builder() {
dispatcher = new Dispatcher();
...
}
Dispatcher主要是实现异步请求任务策略,负责分配异步线程资源,控制异步连接数,只覆盖线程资源层面的逻辑,往下的执行过程对其来说是透明的。对于同步任务,Dispatcher只是简单记录当前运行的任务实体(RealCall),并且是由RealCall主动注册和注销。
你可以通过OkHttpClient.Builder和Dispatvher有参构造函数来指定执行异步任务的线程池。
//这里出于演示目的,只是创建了一个简单的线程池,真正使用需要用户根据自己的应用场景配置自己的线程池。
Executor executor = Executors.newSingleThreadExecutor();
OkHttpClient client = new OkHttpClient
.Builder()
.dispatcher(new Dispatcher(executor))
.build();
应用层协议(Http)实现
//用户自定义拦截器,默认为空,会被添加到Interceptor调用链的最前端
final List<Interceptor> interceptors;
//用户自定义拦截器,默认为空,拦截所有非WebSocket的请求和响应。
//该集合会被添加到Connect完成后和数据发送前的中间
final List<Interceptor> networkInterceptors;
//自定义CookieJar,系统默认只有一个空实现,如果用户想实现Cookie功能,需要自己实现该接口,并且设置到OKHttpClient中。
final CookieJar cookieJar;
//实现了Http协议的缓存规范,默认为空。
final @Nullable Cache cache;
连接池
//连接池
final ConnectionPool connectionPool;
ConnectionPool是一个final类,同时它并没有实现连接池的功能,而是委派给RealConnectionPool来实现:
public final class ConnectionPool {
final RealConnectionPool delegate;
//默认参数
public ConnectionPool() {
this(5, 5, TimeUnit.MINUTES);
}
//用户可以通过该构造方法指定一些线程池的配置参数
public ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
this.delegate = new RealConnectionPool(maxIdleConnections, keepAliveDuration, timeUnit);
}
//下面三个方法都是通过委派给RealConnection实例完成
public int idleConnectionCount() {
return delegate.idleConnectionCount();
}
...
}
ConnectionPool 虽然是不可扩展的,但是你可以通过这样的方式修改ConnectionPool 的默认参数:
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
//最大空闲连接数是10,空闲连接存活时间是15分钟
.connectionPool(new ConnectionPool(10,15, TimeUnit.MINUTES))
.build();
传输层
//代理服务设置,默认为空
final @Nullable Proxy proxy;
//代理选择器,默认为空
//对于Proxy和ProxySelector的使用,小伙伴可以参考JDK官方文档,机翻一下应该看懂也不难。
//https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html
final ProxySelector proxySelector;
//Socket工厂类,默认为DefaultSocketFactory。你可以自定义自己的SocketFacotry。
final SocketFactory socketFactory;
//SSLSocket工厂类,默认SSLSocketFactoryImpl,也可以自定义。
final SSLSocketFactory sslSocketFactory;
//SSL主机名验证
final HostnameVerifier hostnameVerifier;
//下面两个是对SSL证书的处理
final CertificateChainCleaner certificateChainCleaner;
final CertificatePinner certificatePinner;
//代理权限认证
final Authenticator proxyAuthenticator;
//代理权限认证
final Authenticator authenticator;
//DNS解析
final Dns dns;
内部使用类
static {
//OKHttp内部类,主要代理了一些OKHttp重用的内部API,
//方便后序OKHttp升级,如果后期某个API从语义上改变了,只需要修改Internal里面相应的代理方法即可
Internal.instance = new Internal() {
...
}
}
总结
到这里,我们就对OkHttpClient进行了一遍初略的了解,了解它到底有哪些属性,并对这些属性的作用进行了一个简单的归类,同时指出了哪些是可以自定义扩展和配置的。
在后面我们会对OkHttp其他的一些关键的实现类,进行详细的源码分析,如果文章有什么问题,也欢迎大家指出。