Header
注:本文 OkHttp 源码解析基于 v3.8.1 。
OkHttp in GitHub:https://github.com/square/okhttp
现如今,在 Android 开发领域大多数都是选择以 OkHttp 作为网络框架。
然而,简单地会使用 OkHttp 并不能让我们得到满足。更深层次的,我们需要阅读框架的源码,才能用起来得心应手,融会贯通。
An HTTP & HTTP/2 client for Android and Java applications.
这是官网上对于 OkHttp 的介绍,简单明了。同时,也印证了那句经典的话:
Talk is cheap, show me the code.
OkHttp的简单使用方法
OkHttp 使用方法,直接抄官网的 \(╯-╰)/ 。
GET 请求:
1 | OkHttpClient client = new OkHttpClient(); |
POST 请求:
1 | public static final MediaType JSON |
深入源码
在这里,先分析下同步请求的源码,之后再回过头来看异步请求的源码。
Let’s go !
同步请求
OkHttpClient
首先创建一个 OkHttpClient
对象,那我们看看在构造器中做了什么:
1 | public OkHttpClient() { |
在构造器中利用建造者模式来构建 OkHttpClient
的对象。当然,如果你想自定义 OkHttpClient
配置的话,就要 new 一个 OkHttpClient.Builder
来配置自己的参数了。相信大家都干过这种事情了(∩_∩)。
OkHttpClient
的构造器中主要是扎堆扎堆的配置,没别的。
之后再调用 newCall(Request request)
:
1 | @Override |
在方法里面其实是创建了一个 RealCall
的对象,那么我们就进入 RealCall
中去看看吧。
RealCall
在 RealCall
的构造器中只是给一些变量赋值或初始化而已,没什么:
1 | static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { |
然后再把目光转向 RealCall
中的 execute()
方法:
1 | @Override |
execute()
方法为执行该 RealCall
,在方法里面一开始检查了该 call 时候被执行。
然后又加入了 Dispatcher
的 runningSyncCalls
中。runningSyncCalls
队列只是用来记录正在同步请求中的 call ,在 call 完成请求后又会从 runningSyncCalls
中移除。
可见,在同步请求中 Dispatcher
参与的部分很少。但是在异步请求中, Dispatcher
可谓是大展身手。
最重要的方法,那就是 getResponseWithInterceptorChain()
。我们可以看到这方法是直接返回 Response
对象的,所以,在这个方法中一定做了很多很多的事情。
那就继续深入吧:
1 | Response getResponseWithInterceptorChain() throws IOException { |
在 getResponseWithInterceptorChain()
方法中有一堆的拦截器!!!
关于拦截器,之前在 一起来写OKHttp的拦截器 这篇博客中有讲过,若不了解的同学可以先看下。
我们都知道,拦截器是 OkHttp 的精髓。
client.interceptors()
,首先加入interceptors
的是用户自定义的拦截器,比如修改请求头的拦截器等;RetryAndFollowUpInterceptor
是用来重试和重定向的拦截器,在下面我们会讲到;BridgeInterceptor
是用来将用户友好的请求转化为向服务器的请求,之后又把服务器的响应转化为对用户友好的响应;CacheInterceptor
是缓存拦截器,若存在缓存并且可用就直接返回该缓存,否则会向服务器请求;ConnectInterceptor
用来建立连接的拦截器;client.networkInterceptors()
加入用户自定义的networkInterceptors
;CallServerInterceptor
是真正向服务器发出请求且得到响应的拦截器;
最后在聚合了这些拦截器后,利用 RealInterceptorChain
来链式调用这些拦截器,利用的就是责任链模式。
RealInterceptorChain
RealInterceptorChain
可以说是真正把这些拦截器串起来的一个角色。一个个拦截器就像一颗颗珠子,而 RealInterceptorChain
就是把这些珠子串连起来的那根绳子。
进入 RealInterceptorChain
,主要是 proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection)
这个方法:
1 | public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, |
在代码中是一次次链式调用拦截器,可能有些同学还是看不懂。那么,我就捉急地画了一张示意图:
有了这张图就好懂多了,如果还没懂的话就只能自己慢慢体会了。
下面就要进入分析拦截器的步骤了,至于用户自定义的拦截器在这就略过了。还有,拦截器只分析主要的 intercept(Chain chain)
代码。
RetryAndFollowUpInterceptor
1 | @Override |
总体来说,RetryAndFollowUpInterceptor
是用来失败重试以及重定向的拦截器。
BridgeInterceptor
1 | @Override |
在 BridgeInterceptor
这一步,先把用户友好的请求进行重新构造,变成了向服务器发送的请求。
之后调用 chain.proceed(requestBuilder.build())
进行下一个拦截器的处理。
等到后面的拦截器都处理完毕,得到响应。再把 networkResponse
转化成对用户友好的 response
。
CacheInterceptor
1 | @Override |
CacheInterceptor
做的事情就是根据请求拿到缓存,若没有缓存或者缓存失效,就进入网络请求阶段,否则会返回缓存。
ConnectInterceptor
1 | @Override |
这里调用了 streamAllocation.newStream
创建了一个 HttpCodec
的对象。
而 HttpCodec
是一个抽象类,其实现类分别是 Http1Codec
和 Http2Codec
。相对应的就是 HTTP/1.1 和 HTTP/2.0 。
我们来看下 streamAllocation.newStream
的代码:
1 | public HttpCodec newStream(OkHttpClient client, boolean doExtensiveHealthChecks) { |
在 newStream(OkHttpClient client, boolean doExtensiveHealthChecks)
中先在连接池中找到可用的连接 resultConnection
,再结合 sink
和 source
创建出 HttpCodec
的对象。
CallServerInterceptor
1 | @Override |
在 CallServerInterceptor
中可见,关于请求和响应部分都是通过 HttpCodec
来实现的。而在 HttpCodec
内部又是通过 sink
和 source
来实现的。所以说到底还是 IO 流在起作用。
小结
到这里,我们也完全明白了 OkHttp 中的分层思想,每一个 interceptor 只处理自己的事,而剩余的就交给其他的 interceptor 。这种思想可以简化一些繁琐复杂的流程,从而达到逻辑清晰、互不干扰的效果。
异步请求
与同步请求直接调用 execute()
不同的是,异步请求是调用了 enqueue(Callback responseCallback)
这个方法。那么我们对异步请求探究的入口就是 enqueue(Callback responseCallback)
了。
RealCall
1 | @Override |
主要的方法就是调用了 Dispatcher
的 enqueue(AsyncCall call)
方法。这里需要注意的是,传入的是 AsyncCall
对象,而不是同步中的 RealCall
。
那么我们就跟进到 Dispatcher
的源码中吧,至于 AsyncCall
我们会在下面详细讲到。
Dispatcher
1 | synchronized void enqueue(AsyncCall call) { |
从 enqueue(AsyncCall call)
中可以知道,OkHttp 在运行中的异步请求数最多为 63 ,而同一个 host 的异步请求数最多为 4 。否则会加入到 readyAsyncCalls
中。
在加入到 runningAsyncCalls
后,就会进入线程池中被执行。到了这里,我们就要到 AsyncCall
中一探究竟了。
AsyncCall
1 | final class AsyncCall extends NamedRunnable { |
在 AsyncCall
的 execute()
方法中,也是调用了 getResponseWithInterceptorChain()
方法来得到 Response
对象。从这里开始,就和同步请求的流程是一样的,就没必要讲了。
在得到 Response
后,进行结果的回调。
最后,调用了 Dispatcher
的 finished
方法:
1 | void finished(AsyncCall call) { |
在 finished(Deque<T> calls, T call, boolean promoteCalls)
中对该 call 移除。
若在 readyAsyncCalls
中其他的 call ,就移动到 runningAsyncCalls
中并加入线程池中。
这样,完整的流程就循环起来了。
Footer
基本上 OkHttp 的请求响应的流程就讲完了,篇幅有点长长长啊。
不过还有很多点没有涉及到的,比如连接池、缓存策略等等,都是值得我们去深究的。也是需要花很大的功夫才能了解透彻。
好了,那就到这里吧,有问题的同学可以留言。
Goodbye !