OkHttpClient是整个okhttp的大管家,通过它内部的参数,可以自定义各种请求配置
线程管理工具,内部使用 ExecutorService
实现,使用异步请求时,会把请求放入队列中, ExecutorService
来控制什么时候执行
配置代理,是一个枚举,有DIRECT/ HTTP/ SOCKS三个值可以选择
一个List列表,即可以配置支持的Http协议版本
一个List列表,配置支持的TCP协议和SSL/TLS协议版本
建立TCP连接的工厂实现类
建立SSL连接的工厂实现类
建立SSL链接的时候,清除无用证书链,只保留直接的访问的地址的证书
建立SSL链接时,验证证书的有效性
固定证书,通过这个类,可以设置证书的公钥,以及签发这个证书的CA机构及其父类机构的公钥,主要是为了防止 伪造CA机构攻击
权限验证失败后的回调接口,只有在服务器状态码为401时会回到该接口,可以在这里面实现token的刷新操作
管理http连接的重用,减少网络的延迟
域名解析成IP地址的工具,默认使用java提供的DNS解析器
连接池复用的其实是Socket,也就是TCP连接,基于http1.1的keep-alive机制,一个TCP连接在请求结束后并不会关闭,可以被相同的请求重复使用。
复用连接,大大提高了性能,不用每次请求都去建立物理连接
用于协调请求(Call),数据流(Stream),物理连接(RealConnect)。每次请求都会创建一个StreamAllocation,因为连接池复用的关系,存在多个StreamAllocation对应同一个物理连接(RealConnect)的情况。
RealConnect是物理连接的封装,包含了Socket链接(TCP链接),TLS链接。它有一个allocations变量,表示建立该连接上的StreamAllocation的个数,如果allocations长度为0,表示该连接是空闲的,否则表示该连接在被使用。
连接复用的管理类,复用的就是RealConnect。说到复用,肯定少不了对象的存储,获取和清理机制。
ConnectPool用一个双端队列ArrayQueue来存储RealConnect,每创建一个新的链接都会放进连接池中,然后尝试启动清理线程
尝试取出连接的时候,会遍历整个队列,找到合适的链接,然后把RealConnect的allocations计数器加1
ConnectPool的清理机制,允许的最大空闲连接数是5个,每个连接允许的最长空闲时间是5分钟,根据RealConnect中的allocations列表的长度,即建立在此连接上的StreamAllocation的个数是否为0,确定是否为空闲状态
是由一个异步任务实现的,启动的时间是第一次调用put方法后。首先开启while(true)循环,调用cleanup尝试清理,返回下一次清理的等待时间,然后调用wait(time)方法等待后,执行下一次清理,当队列为空时,退出循环结束清理
清理的条件是1.如果某个连接的空闲时间超过5分钟或者空闲连接数超过5个,则清理空闲时间最长的那一个 2.如果都不满足,则等待极限时间和最长空闲时间的那个连接的差值,然后继续清理 3.如果所有的连接都在使用,则等待5分钟,继续清理
http定义了如下的Header来控制缓存
Expires Cache-Control
这2个都是服务端在 response中的header
,表示资源的过期时间,客户端再次请求相同资源的时候,先验证是否过去,没有过期时直接从返回缓存结果,否则重新请求,注意Cache-Control的优先级比Expires要高
last-modified last-modified-since
last-modified服务端返回表示资源上一次修改时间,客户端请求相同资源时用last-modified-since这个header带上服务端返回的资源上一次修改时间,如果资源没有被修改,服务端返回304告知客户端直接复用缓存
ETage if-none-match
ETage是服务端返回表示资源上一次请求的摘要,客户端请求相同资源的时候,使用if-none-match发送上一次资源的摘要,服务端对比摘是否改变,如果没有,返回304告知客户端直接使用缓存
OKhttp的缓存是由CacheInterceptor来完成的,根据不同的缓存策略,决定走网络还是直接从缓存中拿出响应,而缓存的基础就是http定义的缓存控制域
每次请求(直接复用缓存的除外)最终都会调用到RealCall的getResponseWithInterceptorChain()方法,在这个方法中,会把
自定义interceptor RetryAndFollowUpInterceptor BriageInterceptor CacheInterceptor ConnectInterceptor 自定义NetworkInterceptor CallServerInterceptor
按照顺序加入到 interceptors列表
这个变量中,然后使用 interceptors
和 index(此时index=0)
作为参数创建一个 RealInterceptorChain
拦截器链
然后调用 chain.process()
,该方法中会从 interceptors列表
取出第 index
个 interceptor
,再创建一个新的 RealInterceptorChain
拦截器链( index=index+1
),然后执行 interceptor.intercep(chain)
方法,把新的拦截器链作为参数传入,在 interceptor
的 interceptor()
方法中,在做完前置工作后,都会调用 chain.process()
来获取 Response
,如此循环,每一个 interceptor
都被链接了起来
如果当前 interceptor
能够返回 Response
,则直接返回。如果不能,则在 intercep()
方法中,对 request
做各种前置工作,然后调用 chain.process()
,这个方法主要有2个作用
chain
中的变量赋值,提供给后续的 interceptor
使用 interceptor
中获取 response
直到最后一个 CallServerInterceptor
返回 Response
后,层层向上传递,每一个 interceptor
都可以对 response
做各种收尾工作
okhttp是一个非常底层的网络库,实现了应用层协议到建立TCP连接整个过程,并且对外提供了各种配置项,几乎可以应对绝大多数的网络需求。读了okhttp的源码之后,最大的感受就是okhttp强大的可配置和高扩展性,这也是我觉得它的最大优势。
通过protocol可以配置http的版本,并且天然支持http2,http2相比于http1.1新增了多路复用、数据流、报文头压缩的功能,在性能上有了巨大提升,所以,okttp的高性能有一部分来自于http2的支持
通过ConnectSpec可以配置SSL/TLS连接的加密套件的版本,以及加密方式
针对安全性要求很高的场景,可以通过HostnameVerifier自定义证书的验证方式,还可以使用CertificationPinner设置固定的CA公钥,来防止CA篡改攻击
如果有特殊的域名解析规则,可以通过Dns配置自己的域名解析服务
高扩展性的另一个提现就是okhttp的拦截器机制,可以让开发者很方便配置自己的拦截器,方便在数据请求前后各种操作,比如添加Header,打印日志,对resposne做拦截等等都能得心应手
1.因为支持http2,性能相比于http1.1有很大的提升
2.复用连接,每次建立连接后会放入连接池中,下一次相同请求的时候先从看连接池是否有可用的连接,如果有就直接复用,这样不用每次请求都去建立TCP链接,提高了效率。
3.使用okio,okio是对原生Java IO/NIO的封装和优化,其中的缓冲区的设计提高了写数据的性能