OkHttp 研究过程中的疑问与解答思路
本文概述:
- 本文为OkHttp 系列的最后一篇文章,文章简单总结了个人在研究OkHttp 框架中的简单心得体会;例如:OkHttp 请求的整体流程、分发器是如何工作的、拦截器是如何工作的、应用拦截器与网络拦截器的区别、OkHttp 是如何复用TCP 连接的;
OkHttp 请求的整体流程?
-
将Request 对象交给OkHttpClient 的newCall 方法,得到RealCall 对象;
-
在RealCall 对象上执行同步方法
- 直接调用线程,使用五大拦截器执行任务
-
在RealCall 对象上执行异步方法
- 使用分发器,将任务放入线程池中执行,同样使用五大拦截器
分发器是如何工作的?
-
对于同步请求:
- 记录同步任务:将RealCall 对象放入正在执行的同步任务队列中,在请求结束后将这个任务从队列移除并回调异步请求队列的finish 方法(OkHttp 4.X 才有这个的)
-
对于异步请求:
-
将任务加入ready 队列(等待执行),判断是否需要将ready 中的任务放入running 队列并且启动执行
-
什么情况下才能做队列任务移动?
-
同时请求的异步任务数不得大于某一值(默认64)
-
从ready 中取出的异步任务与其相同的host 不得大于某一值(默认为5 )
- 若已经存在5 个相同Host 的异步任务在执行,则继续从ready 中检查下一个任务而不是在这里傻等;
-
-
-
拦截器是如何工作的?
-
整体采用责任链设计模式(将请求者与责任链中的执行者解耦),请求者只需要将任务发给责任链,而不用关心请求过程与细节
-
OkHttp 拦截器有什么?
-
重试重定向:负责拿到本次请求的结果,判断是否需要重定向;如果请求失败,判断是否需要重试;
-
桥接:补全请求头,根据响应头判断并执行GZIP 解压、是否保存Cookie;
-
缓存:如果命中缓存,那么直接将缓存的结果返回上去而不需要再次请求;
-
连接:获取一个连接,仅此而已
-
请求服务:拿到之前已经处理好的连接与request,用这个连接将request 发出去
-
根据HTTP 版本进行Http 报文封装
- 1.X:文本
- 2.0:二进制数据
-
就是用Sokect 的OutputStream 向服务端发送数据,用Socket 的InputStream 接收服务端的回传数据并解析成OkHttp中的Response对象
-
-
应用拦截器与网络拦截器的区别?
-
这两个拦截器都是用户的自定义拦截器
-
添加顺序区别:应用拦截器会被添加在拦截器首位,而网络拦截器会放在所有拦截器的倒数第二个(请求服务拦截器之前一位 )
-
数据获取顺序区别:
- 应用拦截器会第一个拿到请求(用户发起的请求),最后一个接收到响应(经过所有的拦截器处理后的数据 )
- 网络拦截器会倒数第二个接收到请求(真正发起的请求),第二个接收到响应
-
执行成功性:
- 正常情况应用拦截器一定会执行,而网络拦截器则不一定(请求可能通过缓存就拿到了数据 )
-
应用:
- 将日志打印拦截器以应用拦截器的方式注册,其打印的请求是用户提交的原始请求而非真实处理后的,而添加到网络拦截器中,这个打印的就是真实发出的请求;
OkHttp 是如何复用TCP 连接的?
-
在OkHttp 中设计了一个连接池,其中存在一个容器缓存了所有的有效连接对象;
-
当需要请求时,那么就去连接池中找对应的现成的连接对象(DNS 解析相同、Host 相同,IP 相同、证书要配置得一样、HostName(Host 的验证对象)、SokectXXX、代理、代理选择器HTTP 版本信息相同等) 这样才能完成连接的复用
-
连接池会清理垃圾连接
- 什么是垃圾连接:空闲时间超过五分钟
- 闲置链接数超过五个:LRU 清理空闲连接,直到空闲连接数小于五
总结:
- OkHttp 实质上是使用Java 完成了对Socket 的封装,帮助实现了HTTP 通信;
\