本系列文章:
OkHttp源码彻底解析(三)OkHttp3.0拦截器原理——责任链模式
目录
连接池是用来管理和复用网络连接对象的,而网络连接的主角就是Connection/RealConnection.
OkHttp连接池
OkHttp3将客户端与服务器之间的连接抽象为Connection/RealConnection,为了管理这些连接的复用而设计了ConnectionPool。共享相同Address
的请求可以复用连接
连接池的意义——KeepAlive机制
复用连接,减少了频繁的网络请求导致性能下降的问题。我们知道,Http是基于TCP协议的,而TCP建立连接需要经过三次握手,断开需要经过四次挥手,因此,Http中添加了一种KeepAlive机制,当数据传输完毕后仍然保持连接,等待下一次请求时直接复用该连接。
一次响应的流程
在高并发的请求连接情况下或者同个客户端多次频繁的请求操作,无限制的创建会导致性能低下。
如果使用keep-alive
在timeout
空闲时间内,连接不会关闭,相同重复的request将复用原先的connection
,减少握手的次数,大幅提高效率。
并非
keep-alive
的timeout设置时间越长,就越能提升性能。长久不关闭会造成过多的僵尸连接和泄露连接出现。
从拦截器流程了解连接池
在讲解连接池之前,先了解OkHttp的拦截器
OkHttp拦截器流程图
上面的拦截器分别是:
1.失败重连拦截器:
一个循环来不停的获取response。每循环一次都会获取下一个request,如果没有,则返回response,退出循环。而获取下一个request的逻辑,是根据上一个response返回的状态码,分别作处理。
2.桥接拦截器:
请求从应用层数据类型类型转化为网络调用层的数据类型。将网络层返回的数据类型 转化为 应用层数据类型。(补足缺失的请求头等)
3.缓存拦截器:
CacheInterceptor主要作用是将请求 和 返回 关连得保存到缓存中。客户端与服务端根据一定的机制,在需要的时候使用缓存的数据作为网络请求的响应,节省了时间和带宽。
4.连接拦截器
与请求服务器的拦截器是网络交互的关键。为请求服务器拦截器建立可用的连接,创建用于网络IO流 的RealConnection对象
5.请求服务器的拦截器:
完成了最后发起网络请求的工作。将HTTP请求写入网络IO流,从IO流读取网络数据。
与连接拦截器要划分为两个拦截器,除了解耦之外,更重要的是在这两个流程之间还可以插入一个专门为WebSocket服务的拦截器( WebSocket一种在单个 TCP 连接上进行全双工通讯的协议,本文不做详解)。
关于这部分不具体展开,感兴趣可以看我的另外两篇博客,可以说是非常详细地介绍了拦截器的原理及应用
其中,与连接池相关的是失败重连拦截器与连接拦截器
1.RetryAndFollowUpInterceptor将创建的StreamAllocation
对象传递给后面执行的Interceptor
2.ConnectInterceptor
从RealInterceptorChain
获取前面的Interceptor传过来的StreamAllocation
对象,执行 streamAllocation.newStream()
完成前述所有的连接建立工作,创建的用于网络IO的RealConnection对象,以及对于与服务器交互最为关键的HttpCodec等对象传递给后面的Interceptor,也就是CallServerInterceptor
。
streamAllocation.newStream()新建了IO流,将请求序列化发到网络,将网络数据反序列化并接收
(请求服务器的拦截器)。
RealConnection底层连接着Socket,就是实现了跨进程与网络上其他设备交互的底层实现。
连接池ConnectionPool的创建
OkHttp3的用户可以自行创建ConnectionPool,对最大空闲连接数及连接的保活时间进行配置,并在OkHttpClient创建期间,将其传给OkHttpClient.Builder,在OkHttpClient中启用它。没有定制连接池的情况下,则在OkHttpClient.Builder构造过程中以默认参数
默认情况下,ConnectionPool
最多保存 5个 处于空闲状态的连接,且连接的默认保活时间为 5分钟。也就是默认支持5个并发Socket连接,默认的keepAlive时间为5分钟,当然我们可以在构建OkHttpClient时设置不同的值
连接池的缓存操作
ConnectionPool
提供对Deque<RealConnection>
进行操作的方法分别为put
、get
、connectionBecameIdle
、evictAll
几个操作。分别对应放入连接、获取连接、移除连接、移除所有连接操作。
遍历connections缓存列表,当某个连接计数的次数小于限制的大小以及request的地址和缓存列表中此连接的地址完全匹配。则直接复用缓存列表中的connection作为request的连接。