转载自:http://www.ishenping.com/ArtInfo/69561.html

1、okhttp工作的大致流程

1.1、整体流程

(1)、当我们通过OkhttpClient创建一个Call,并发起同步或异步请求时;
(2)、okhttp会通过Dispatcher对我们所有的RealCall(Call的具体实现类)进行统一管理,并通过execute()及enqueue()方法对同步或异步请求进行处理;
(3)、execute()及enqueue()这两个方法会最终调用RealCall中的getResponseWithInterceptorChain()方法,从拦截器链中获取返回结果;
(4)、拦截器链中,依次通过RetryAndFollowUpInterceptor(重定向拦截器)、BridgeInterceptor(桥接拦截器)、CacheInterceptor(缓存拦截器)、ConnectInterceptor(连接拦截器)、CallServerInterceptor(网络拦截器)对请求依次处理,与服务的建立连接后,获取返回数据,再经过上述拦截器依次处理后,最后将结果返回给调用方。
提供两张图便于理解和记忆:

 
okhttp整体流程1
 
okhttp整体流程2

这张图只画出了请求流程,没有数据返回流程,后期会处理。

1.2、各大拦截器的原理解析

1.2.1、RetryAndFollowUpInterceptor:负责重定向

构建一个StreamAllocation对象,然后调用下一个拦截器获取结果,从返回结果中获取重定向的request,如果重定向的request不为空的话,并且不超过重定向最大次数的话就进行重定向,否则返回结果。注意:这里是通过一个while(true)的循环完成下一轮的重定向请求。

(1)、StreamAllocation为什么在第一个拦截器中就进行创建?
???????便于取消请求以及出错释放资源。
(2)、StreamAllocation的作用是什么?
???????StreamAllocation负责统筹管理Connection、Stream、Call三个实体类,具体就是为一个Call(Realcall),寻找( findConnection() )一个Connection(RealConnection),获取一个Stream(HttpCode)。

1.2.2、BridgeInterceptor

负责将原始Requset转换给发送给服务端的Request以及将Response转化成对调用方友好的Response,具体就是对request添加Content-Type、Content-Length、Connection、Accept-Encoding等请求头以及对返回结果进行解压等。

1.2.3、CacheInterceptor

CacheInterceptor:负责读取缓存以及更新缓存。
在请求阶段:

  1. 读取候选缓存cacheCandidate;
  2. 根据originOequest和cacheresponse创建缓存策略CacheStrategy;
  3. 根据缓存策略,来决定是否使用网络或者使用缓存或者返回错误。
    具体的的缓存策略就是http的缓存策略,详见下图:
    在结果返回阶段:
    负责将网络结果进行缓存(使用于DiskLruCache)。
 
okhttp&http缓存策略

强制缓存:当客户端第一次请求数据是,服务端返回了缓存的过期时间(Expires与Cache-Control),没有过期就可以继续使用缓存,否则则不适用,无需再向服务端询问。
对比缓存:当客户端第一次请求数据时,服务端会将缓存标识(Etag/If-None-Match与Last-Modified/If-Modified-Since)与数据一起返回给客户端,客户端将两者都备份到缓存中 ,再次请求数据时,客户端将上次备份的缓存
标识发送给服务端,服务端根据缓存标识进行判断,如果返回304,则表示缓存可用,如果返回200,标识缓存不可用,使用最新返回的数据。

ETag是用资源标识码标识资源是否被修改,Last-Modified是用时间戳标识资源是否被修改。ETag优先级高于Last-Modified。

1.2.4、ConnectInterceptor:负责与服务器建立连接

使用StreamAllocation.newStream来和服务端建立连接,并返回输入输出流(HttpCodec),实际上是通过StreamAllocation中的findConnection寻找一个可用的Connection,然后调用Connection的connect方法,使用socket与服务端建立连接。

1.2.5、CallServerInterceptor:负责从服务器读取响应的数据

主要的工作就是把请求的Request写入到服务端,然后从服务端读取Response。
(1)、写入请求头
(2)、写入请求体
(3)、读取响应头
(4)、读取响应体

2、连接池原理

由于HTTP是基于TCP,TCP连接时需要经过三次握手,为了加快网络访问速度,我们可以Reuqst的header中将Connection设置为keepalive来复用连接。

Okhttp支持5个并发KeepAlive,默认链路生命为5分钟(链路空闲后,保持存活的时间),连接池有ConectionPool实现,对连接进行回收和管理。

2.1、连接池的清理

 
连接池清理1

在ConectionPool中有一个异步线程去清理连接池中的连接,首先通过cleanup方法执行清理,然后等待clean返回的时间后,再次进行清理,以此循环,持续清理。

 
连接池原理2

1、首先统计空闲连接数量;
2、然后通过for循环查找最长空闲时间的连接以及对应空闲时长;
3、然后判断这个最长空闲时间的连接是否超出最大空闲连接数或者或者超过最大空闲时间,满足其一则清除最长空闲的连接。如果不满足清理条件,则返回一个对应等待时间。
这个对应等待的时间又分二种情况:
1 有空闲连接:则返回:keepAliveDurationNs-longestIdleDurationNs;
2 没有空闲的连接,则返回:keepAliveDurationNs
注意:清除一个空闲连接后,会返回0,再次立即开始清理。

如何统计空闲连接呢?

 
统计空闲连接

StreamAllocation创建一个Connection后会将自己添加到Connection的connection.allocations列表中,数据读取完毕之后,会将自己从Connection的connection.allocations中移除,所以判读一个Connection是否是空闲连接可以采用引用计数法,判断connection.allocations列表中是否有StreamAllocation,如果没有就是空闲连接,否则不是。

3、参考链接

因为本文是极度针对面试的,所以未解释过多名词和粘贴过多代码,如果不明白其中原理,可以参考下面两篇链接:
3.1、https://www.jianshu.com/p/6166d28983a2
3.2、https://juejin.im/post/5a704ed05188255a8817f4c9#heading-15

okhttp浅析的更多相关文章

  1. 一些你可能需要的okhttp实现

    https://blog.csdn.net/qq_17766199/article/details/53186874 今天分享一些我在项目中使用到的okhttp实现,由简至难.(以下内容均在okhtt ...

  2. 学会Retrofit+OkHttp+RxAndroid三剑客的使用,让自己紧跟Android潮流的步伐

    http://blog.csdn.net/iamzgx/article/details/51607387 概括 在上一篇博客android网络框架OkHttp之get请求(源码初识) 讲解了OkHtt ...

  3. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  4. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  5. 高性能IO模型浅析

    高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking  ...

  6. netty5 HTTP协议栈浅析与实践

      一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...

  7. Jvm 内存浅析 及 GC个人学习总结

    从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言.这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序.今天我们就来说说Java的一项基本但非常重要的技术内存管理 了解C ...

  8. 从源码浅析MVC的MvcRouteHandler、MvcHandler和MvcHttpHandler

    熟悉WebForm开发的朋友一定都知道,Page类必须实现一个接口,就是IHttpHandler.HttpHandler是一个HTTP请求的真正处理中心,在HttpHandler容器中,ASP.NET ...

  9. 【深入浅出jQuery】源码浅析2--奇技淫巧

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

随机推荐

  1. [Linux]centos下安装memcached

    一.yum安装 1.Linux系统安装memcached,首先要先安装libevent库. yum install libevent libevent-devel 2.安装memcached yum ...

  2. git版本对比

    1.git diff版本比对 (未添加到暂存区间之前的区别对比) 未进行修改,则显示为空 进行文件修改,再执行git diff 当执行git add .  之后,再次git diff则为空 缓存和提交 ...

  3. HTML连载53-网易注册界面实战之content的头部、content注册信息

    一. 这次完成了content部分的右边图片以及content的top部分的边角填充 <!DOCTYPE html> <html lang="en"> &l ...

  4. JavaScript的函数以及循环和判断

    1.什么是函数? 这个函数跟我们数学当中的函数不太一样,我们这个函数是一段定义好的代码,可以循环使用,(这样我们更方便). 2.函数的作用: 提升代码的可复用性,将一定代码进行预定义,需要的时候才触发 ...

  5. Python迭代器(函数名的应用,新版格式化输出)

    1. 函数名的运用 ​ 你们说一下,按照你们的理解,函数名是什么? ​ 函数名的定义和变量的定义几乎一致,在变量的角度,函数名其实就是一个变量,具有变量的功能:可以赋值:但是作为函数名他也有特殊的功能 ...

  6. SpringCloud(七):springcloud-config统一管理配置中心

    前言: Spring Cloud Config组件是独立的,不需要注册到eureka.config工作原理是把读取目标到配置拉取到本地缓存一份然后供给其他客户端使用,所以一旦config启动成功,可以 ...

  7. spark SQL、RDD、Dataframe总结

  8. socket经典案例-发送数据

    一:客户端向服务端发送数据. 服务端: package com.company.s; import java.io.*; import java.net.ServerSocket; import ja ...

  9. jQuery从零开始(一)

    1.jQuery是什么? 轻量级的工具库,类库. Jquery可以写的很少的代码,干的很多的事情. 2.学习心态,常用的功能 jQuery只是一个工具,它的实现原理还是js.以练习为主,多看多练. 常 ...

  10. WebMagic使用代理ip爬数据解决HTTP407问题

    手头一个小活儿是爬竞品网站数据.使用webmagic来实现.光公司ip不行,被封了就会影响业务正常访问.刚好公司另一个项目购买了代理IP资源“站大爷”,那个项目夭折了,于是申请借来用用. 调通站大爷提 ...