OkHttp 3.7源码分析(一)——整体架构
来源:互联网 发布:医疗软件注册证 编辑:程序博客网 时间:2024/05/22 14:46
OkHttp是一个处理网络请求的开源项目,是Android端最火热的轻量级框架,由移动支付Square公司贡献用于替代HttpUrlConnection和Apache HttpClient。随着OkHttp的不断成熟,越来越多的android开发者使用OkHttp作为网络框架。
之所以可以赢得如此多开发者的喜爱,主要得益于如下特点:
- 支持HTTPS/HTTP2/WebSocket(在OkHttp3.7中已经剥离对Spdy的支持,转而大力支持HTTP2)
- 内部维护任务队列线程池,友好支持并发访问
- 内部维护连接池,支持多路复用,减少连接创建开销
- socket创建支持最佳路由
- 提供拦截器链(InterceptorChain),实现request与response的分层处理(如透明GZIP压缩,logging等)
为了一探OkHttp是如何具备以下特点的,笔者反复研究OkHttp框架源码,力求通过源码分析向各位解释一二。所以特意准备了几篇博客跟大家一起探讨下OkHttp的方方面面,今天首先从整体架构上分析下OkHttp。
简单使用
首先来看下OkHttp的简单使用,OkHttp提供了两种调用方式:
- 同步调用
- 异步调用
同步调用
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
首先加锁置标志位,接着使用分配器的executed方法将call加入到同步队列中,然后调用getResponseWithInterceptorChain方法(稍后分析)执行http请求,最后调用finishied方法将call从同步队列中删除
异步请求
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
同样先置标志位,然后将封装的一个执行体放到异步执行队列中。这里面引入了一个新的类AsyncCall,这个类继承于NamedRunnable,实现了Runnable接口。NamedRunnable可以给当前的线程设置名字,并且用模板方法将线程的执行体放到了execute方法中
拦截器
除了同步调用和异步调用,OkHttp还提供了一个拦截器的概念。拦截器提供了拦截请求和拦截服务器应答的接口。OkHttp提供了一个拦截器链的概念,通过将一个个拦截器组合成一个拦截器链,可以达到在不同层面做不同拦截操作的效果,有点AOP的意思。具体拦截器的使用可以参考:Okhttp-wiki 之 Interceptors 拦截器
总体架构
上图是OkHttp的总体架构,大致可以分为以下几层:
- Interface——接口层:接受网络访问请求
- Protocol——协议层:处理协议逻辑
- Connection——连接层:管理网络连接,发送新的请求,接收服务器访问
- Cache——缓存层:管理本地缓存
- I/O——I/O层:实际数据读写实现
- Inteceptor——拦截器层:拦截网络访问,插入拦截逻辑
Interface——接口层:
接口层接收用户的网络访问请求(同步请求/异步请求),发起实际的网络访问。OkHttpClient
是OkHttp框架的客户端,更确切的说是一个用户面板。用户使用OkHttp进行各种设置,发起各种网络请求都是通过OkHttpClient
完成的。每个OkHttpClient
内部都维护了属于自己的任务队列,连接池,Cache,拦截器等,所以在使用OkHttp作为网络框架时应该全局共享一个OkHttpClient
实例。
Call
描述一个实际的访问请求,用户的每一个网络请求都是一个Call
实例。Call
本身只是一个接口,定义了Call
的接口方法,实际执行过程中,OkHttp会为每一个请求创建一个RealCall
,每一个RealCall
内部有一个AsyncCall
:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
AsyncCall
继承的NamedRunnable
继承自Runnable接口:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
所以每一个Call就是一个线程,而执行Call的过程就是执行其execute
方法的过程。
Dispatcher
是OkHttp的任务队列,其内部维护了一个线程池,当有接收到一个Call
时,Dispatcher
负责在线程池中找到空闲的线程并执行其execute
方法。这部分将会单独拿一篇博客进行介绍,详细内容可参考本系列接下来的文章。
Protocol——协议层:处理协议逻辑
Protocol层负责处理协议逻辑,OkHttp支持Http1/Http2/WebSocket协议,并在3.7版本中放弃了对Spdy协议,鼓励开发者使用Http/2。
Connection——连接层:管理网络连接,发送新的请求,接收服务器访问
连接层顾名思义就是负责网络连接。在连接层中有一个连接池,统一管理所有的Socket连接,当用户新发起一个网络请求时,OkHttp会首先从连接池中查找是否有符合要求的连接,如果有则直接通过该连接发送网络请求;否则新创建一个网络连接。
RealConnection
描述一个物理Socket连接,连接池中维护多个RealConnection实例。由于Http/2支持多路复用,一个RealConnection
可以支持多个网络访问请求,所以OkHttp又引入了StreamAllocation
来描述一个实际的网络请求开销(从逻辑上一个Stream
对应一个Call
,但在实际网络请求过程中一个Call
常常涉及到多次请求。如重定向,Authenticate等场景。所以准确地说,一个Stream
对应一次请求,而一个Call
对应一组有逻辑关联的Stream
),一个RealConnection
对应一个或多个StreamAllocation
,所以StreamAllocation
可以看做是RealConenction
的计数器,当RealConnection
的引用计数变为0,且长时间没有被其他请求重新占用就将被释放。
连接层是OkHttp的核心部分,这部分当然也会单独拿一篇博客详细讲解,详细内容可参考本专题相关文章。
Cache——缓存层:管理本地缓存
Cache层负责维护请求缓存,当用户的网络请求在本地已有符合要求的缓存时,OkHttp会直接从缓存中返回结果,从而节省网络开销。这部分内容也会单独拿一篇博客进行介绍,详细内容可参考本专题相关文章。
I/O——I/O层:实际数据读写实现
I/O层负责实际的数据读写。OkHttp的另一大有点就是其高效的I/O操作,这归因于其高效的I/O库okio
这部分内容笔者也打算另开一个专题进行介绍。详细内容可以参考本博客相关内容。
Inteceptor——拦截器层:拦截网络访问,插入拦截逻辑
拦截器层提供了一个类AOP接口,方便用户可以切入到各个层面对网络访问进行拦截并执行相关逻辑。在下一篇博客中,笔者将通过介绍一个实际的网络访问请求实例来介绍拦截器的原理。
转自:http://blog.csdn.net/asialiyazhou/article/details/72598320
- OkHttp 3.7源码分析(一)——整体架构
- OkHttp 3.7源码分析(一)——整体架构
- OkHttp源码解析(一)——整体流程(上)
- OkHttp源码解析(一)——整体流程(上)
- Reids源码分析(一)——整体结构分析
- jQuery-1.9.1源码分析系列(一)整体架构
- Docker源码分析(一)之整体架构图
- OkHttp源码解析(二)——整体流程(下)
- OkHttp源码解析(二)——整体流程(下)
- OKHttp源码分析(一)
- OkHttp源码分析(一)
- canal源码分析——整体架构分析
- Spark源码分析——Spark整体架构
- 【jQuery源码浅析】(一)--整体架构
- Mongodb 源码分析:整体架构
- OkHttp 3.7源码分析(三)——任务队列
- OkHttp 3.7源码分析(四)——缓存策略
- OkHttp 3.7源码分析(五)——连接池
- 使用jmeter进行APP接口测试经验总结
- 内连接、左外连接、右外连接、交叉连接区别
- mysql root登录报错问题
- Android开发:清空缓存
- 005_镜像分层
- OkHttp 3.7源码分析(一)——整体架构
- Android SDK platforms build-tools等镜像下载
- kibana 查询语法
- 调用react-native-fs插件时,如果数据的接口是需要验证信息的,在android上运行报错
- 线段树小结
- jquery遍历表格获取每行数据及每个单元格数据
- js中__proto__和prototype的区别和关系
- iOS 开发流程
- Qt 应用程序添加图标