(1)、当咱们经过OkhttpClient建立一个Call,并发起同步或异步请求时;
(2)、okhttp会经过Dispatcher对咱们全部的RealCall(Call的具体实现类)进行统一管理,并经过execute()及enqueue()方法对同步或异步请求进行处理;
(3)、execute()及enqueue()这两个方法会最终调用RealCall中的getResponseWithInterceptorChain()方法,从拦截器链中获取返回结果;
(4)、拦截器链中,依次经过RetryAndFollowUpInterceptor(重定向拦截器)、BridgeInterceptor(桥接拦截器)、CacheInterceptor(缓存拦截器)、ConnectInterceptor(链接拦截器)、CallServerInterceptor(网络拦截器)对请求依次处理,与服务的创建链接后,获取返回数据,再通过上述拦截器依次处理后,最后将结果返回给调用方。
提供两张图便于理解和记忆:html
这张图只画出了请求流程,没有数据返回流程,后期会处理。面试
构建一个StreamAllocation对象,而后调用下一个拦截器获取结果,从返回结果中获取重定向的request,若是重定向的request不为空的话,而且不超太重定向最大次数的话就进行重定向,不然返回结果。注意:这里是经过一个while(true)的循环完成下一轮的重定向请求。缓存
(1)、StreamAllocation为何在第一个拦截器中就进行建立?
???????便于取消请求以及出错释放资源。
(2)、StreamAllocation的做用是什么?
???????StreamAllocation负责统筹管理Connection、Stream、Call三个实体类,具体就是为一个Call(Realcall),寻找( findConnection() )一个Connection(RealConnection),获取一个Stream(HttpCode)。服务器
负责将原始Requset转换给发送给服务端的Request以及将Response转化成对调用方友好的Response,具体就是对request添加Content-Type、Content-Length、Connection、Accept-Encoding等请求头以及对返回结果进行解压等。网络
CacheInterceptor:负责读取缓存以及更新缓存。
在请求阶段:并发
强制缓存:当客户端第一次请求数据是,服务端返回了缓存的过时时间(Expires与Cache-Control),没有过时就能够继续使用缓存,不然则不适用,无需再向服务端询问。
对比缓存:当客户端第一次请求数据时,服务端会将缓存标识(Etag/If-None-Match与Last-Modified/If-Modified-Since)与数据一块儿返回给客户端,客户端将二者都备份到缓存中 ,再次请求数据时,客户端将上次备份的缓存
标识发送给服务端,服务端根据缓存标识进行判断,若是返回304,则表示缓存可用,若是返回200,标识缓存不可用,使用最新返回的数据。异步
ETag是用资源标识码标识资源是否被修改,Last-Modified是用时间戳标识资源是否被修改。ETag优先级高于Last-Modified。socket
使用StreamAllocation.newStream来和服务端创建链接,并返回输入输出流(HttpCodec),其实是经过StreamAllocation中的findConnection寻找一个可用的Connection,而后调用Connection的connect方法,使用socket与服务端创建链接。post
主要的工做就是把请求的Request写入到服务端,而后从服务端读取Response。
(1)、写入请求头
(2)、写入请求体
(3)、读取响应头
(4)、读取响应体spa
因为HTTP是基于TCP,TCP链接时须要通过三次握手,为了加快网络访问速度,咱们能够Reuqst的header中将Connection设置为keepalive来复用链接。
Okhttp支持5个并发KeepAlive,默认链路生命为5分钟(链路空闲后,保持存活的时间),链接池有ConectionPool实现,对链接进行回收和管理。
在ConectionPool中有一个异步线程去清理链接池中的链接,首先经过cleanup方法执行清理,而后等待clean返回的时间后,再次进行清理,以此循环,持续清理。
一、首先统计空闲链接数量;
二、而后经过for循环查找最长空闲时间的链接以及对应空闲时长;
三、而后判断这个最长空闲时间的链接是否超出最大空闲链接数或者或者超过最大空闲时间,知足其一则清除最长空闲的链接。若是不知足清理条件,则返回一个对应等待时间。
这个对应等待的时间又分二种状况:
1 有空闲链接:则返回:keepAliveDurationNs-longestIdleDurationNs;
2 没有空闲的链接,则返回:keepAliveDurationNs
注意:清除一个空闲链接后,会返回0,再次当即开始清理。
如何统计空闲链接呢?
StreamAllocation建立一个Connection后会将本身添加到Connection的connection.allocations列表中,数据读取完毕以后,会将本身从Connection的connection.allocations中移除,因此判读一个Connection是不是空闲链接能够采用引用计数法,判断connection.allocations列表中是否有StreamAllocation,若是没有就是空闲链接,不然不是。
由于本文是极度针对面试的,因此未解释过多名词和粘贴过多代码,若是不明白其中原理,能够参考下面两篇连接:
3.一、https://www.jianshu.com/p/6166d28983a2
3.二、http://www.javashuo.com/article/p-mvwpcnbi-hs.html