前言
最近在看 OkHttp 原理,发现网上很多都是对源码的行级别的分析,感觉再写一篇意义不大,主要还是看背后的设计思想和设计模式,记录一下自己的所看所想,所以本篇不会有大段的源码分析和细节,更多的是在更高的层面进行总结。
写这篇文章一是好记性不如烂笔头,二是文笔太菜想练练文笔,大家轻喷哈~
看完本文,你会对以下知识点有所了解:
- 网络模型
- HTTP 协议
- TCP 长连接
- 多路复用
- 设计模式
- 建造者模式
- 责任链模式
网络协议
OSI 网络模型
说到网络协议,那绕不开 OSI 七层模型:
重点看应用层、传输层和网络层,我们要发送的请求和数据会先通过 HTTP 协议进行一次封装,然后经过 TCP 协议三次握手与服务器建立连接,然后通过 IP 找到需要发送的地址。
HTTP 历代版本
HTTP 历代版本的区别:
-
HTTP/1.0小菜鸟,一次 TCP 连接对应一次 HTTP 通信。耗时、低效。 -
HTTP/1.1稍有改观,使用 Connection:Keep-Alive 实现 TCP 长连接,不过 HTTP 通信是串行的,还是耗时。 -
HTTP/2.0老大哥,实现了 HTTP 并行通信,基于流和帧封装实现,简单理解就是把数据切块,以块为单位发送,快速、强大。
TCP + OkHttp 实现多路复用
运用 Keep-Alive 可以实现 TCP 长连接,可是光有 HTTP 这边的 Keep-Alive 是不够的,还需要客户端配合它来实现,OkHttp 的ConnectionPool 类实现了 TCP 连接的复用。
简单的看下实现:
public final class RealConnectionPool {
private static final Executor executor = new ThreadPoolExecutor(...);
private final Runnable cleanupRunnable = () -> {
cleanup(System.nanoTime());
}
};
private final Deque<RealConnection> connections = new ArrayDeque<>();
}
删去多余代码后,可以发现使用了一个队列存放连接,使用了一个线程来清除废弃的连接。至于清除废弃连接的原理等,这里不展开了。
OkHttp
RealCall 的构造器值得看一下:
final class RealCall implements Call {
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
}
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.transmitter = new Transmitter(client, call);
return call;
}
}
从静态方法 newRealCall 中可以看到,实例化 RealCall 需要两个步骤,所以用静态方法封装了,这个技巧我们在业务中也可以使用起来。
异步请求流程
一个异步网络请求从出生到获取服务器响应的流程:
Activity通过OkHttpClient获得一个CallActivity使用Call.enqueue回调方法开始一个异步网络请求Call内部会生成一个AsyncCall,由AsyncCall负责异步调用网络请求和结果的回调Dispatcher把asyncCall放入线程池DiapatcherExecutorService- 线程池调用
asyncCall#run asyncCall通过InterceptorChain的几个拦截器的处理,获得最终的response,最后通过回调把response给Activity
从另一个角度看流程:
简要概括异步网络请求的全流程:OkHttpClient 根据我们提供的 request 生成一个 call,并放入 Dispatcher 中,这个 call 经由 Dispatcher 的线程池捞出来执行,通过一个个拦截器的处理后,到达服务器,服务器返回的 response 再经过这几个拦截器的处理,得到了最终的结果。拦截器这块要细细分析的话又是一篇文章了。
设计模式
OkHttp 用到的一些设计模式:
-
因为
OkHttpClient的实例化需要很多的参数,大部分参数是有默认实现的,所以使用了建造者模式。同理,Request和Response的初始化也用了建造者模式。 -
http 的处理过程有多个步骤,比如
headers的处理、重定向、缓存、长连接等,如果把这些功能都写在一个类里,那这个类会很臃肿,可读性可扩展性差,所以这些步骤被多个类分别实现,每个类各司其职,同时,处理好的数据需要流转给下一个步骤,所以很自然的想到使用责任链模式实现,遂形成了 OkHttp 的核心功能:拦截器 -
用工厂模式生成
RealCall,OkHttpClient是个工厂,使用者只需要调用OkHttpClient就行,无需关心new RealCall的细节。
总结
本篇介绍了 HTTP 协议和 TCP 协议的长连接部分,然后引出 OkHttp 中对长连接的实现。简单过了一下使用 OkHttp 进行异步请求的流程。介绍了 OkHttp 用到的设计模式。除了这些,还有很多的地方没有覆盖到,比如拦截器的实现,连接池原理、缓存等,以后再填坑。