✨作者简介:00后,22年刚刚毕业,一枚在鹅厂搬砖的程序员。
✨前置任务:学习此篇文章之前读者可以自行阅读上一篇文章OkHttp第一篇—使用与分发机制。此篇文章需要读者了解责任链模式,如果不太了解可以看笔者的这篇文章设计模式之责任链模式。
✨学习目标:验证
OkHttp
的责任链模式,并分析其运行原理。
✨创作初衷:学习
OkHttp
的原理,阅读Kotlin
框架源码,提高自己对Kotlin
代码的阅读能力。为了读代码而读代码,笔者知道这是不对的,但作为应届生,提高阅读源码的能力笔者认为还是很重要的。
OkHttp第二篇-OkHttp的责任链模式
OkHttp Response
的返回整体流程属于责任链模式,本篇文章重点分析其中的责任链模式。
先说结论:OkHttp
中有一个链条类,以及许多节点类,节点可以放在链条上,将需要发送的Request
交给链条,启动链条,首节点就可以对Request
进行加工并继续向下传递,最后一个节点将请求发出,当最后一个节点收到Response
后,逐步向上传递,最终回到首节点。
流程如下图:
黑线代表Request
的流向,红线代表Response
的流向,在流向的过程中上游可以对下游的Request或Response进行加工处理。
在OkHttp原理第一篇—使用与分发机制中我们得出结论,无论异步请求还是同步请求,Response
都是调用RealCall
中的 getResponseWithInterceptorChain()
方法返回的,因此我们在从方法开始分析。
RealCall#getResponseWithInterceptorChain
@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
//初始化拦截器数组
val interceptors = mutableListOf<Interceptor>()
interceptors += client.interceptors //用户自定义的节点,可在构建Client时加入自己的节点
interceptors += RetryAndFollowUpInterceptor(client)
interceptors += BridgeInterceptor(client.cookieJar)
interceptors += CacheInterceptor(client.cache)
interceptors += ConnectInterceptor
//是否属于webSocket协议链接,若是则添加networkInterceptors
if (!forWebSocket) {
interceptors += client.networkInterceptors
}
interceptors += CallServerInterceptor(forWebSocket)
//创建Chain链条
val chain = RealInterceptorChain(
call = this, //当前请求的Call(Request的载体)
interceptors = interceptors, //节点数组
index = 0, //目前需要执行的节点下标
exchange = null,
request = originalRequest, //原先的请求,后续会对请求进行再次封装
connectTimeoutMillis = client.connectTimeoutMillis, //超时时间
readTimeoutMillis = client.readTimeoutMillis,
writeTimeoutMillis = client.writeTimeoutMillis
)
...
//链条执行,下面分析
val response = chain.proceed(originalRequest)
...
return response
...
}
以HTTP
请求分析,去掉自定义节点,此时链条会存在5
个节点(在OkHttp
中节点叫做拦截器,下文中全部使用拦截器):
RetryAndFollowUpInterceptor
重试与重定向拦截器,主要处理错误信息进行重试和重定向操作BridgeInterceptor
桥接拦截器,对HTTP
请求头进行封装,并处理请求体的压缩CacheInterceptor
缓存拦截器, 处理HTTP
的缓存操作ConnectInterceptor
连接拦截器,建立Socket
连接CallServerInterceptor
请求拦截器,对Socket
的输入流和输出流进行操作,真正的请求发起者和相应接收者
上述拦截器的作用还无需理解,此小节重点分析OkHttp的责任链的执行过程。
@Throws(IOException::class)
override fun proceed(request: Request): Response {
...
//创建一个新的链条,使当前下标加1,看下1中分析copy函数
val next = copy(index = index + 1, request = request)
val interceptor = interceptors[index]
@Suppress("USELESS_ELVIS")
//执行节点的处理,将下标加1的next链条交给当前拦截器,看下2,分析当前节点如何启动下一个节点
val response = interceptor.intercept(next) ?: throw NullPointerException(
"interceptor $interceptor returned null")
...
return response
}
1.RealInterceptorChain#copy
返回一个新的RealInterceptorChain
internal fun copy(
index: Int = this.index,
exchange: Exchange? = this.exchange,
request: Request = this.request,
connectTimeoutMillis: Int = this.connectTimeoutMillis,
readTimeoutMillis: Int = this.readTimeoutMillis,
writeTimeoutMillis: Int = this.writeTimeoutMillis
) = RealInterceptorChain(call, interceptors, index, exchange, request, connectTimeoutMillis,
readTimeoutMillis, writeTimeoutMillis)
2.RetryAndFollowUpInterceptor,BridgeInterceptor,CacheInterceptor,ConnectInterceptor#intercept
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
var request = chain.request
//对Request进行处理
...
//进行递归,回到上的proceed()方法,此时index下标已经+1,执行下一个拦截器的处理
response = realChain.proceed(request)
//对response进行处理
...
return response
}
前四个拦截器的处理方法类似,第五个拦截器会有所不同,其Response
会直接通过网路返回的数据进行构建,不会再往下传递。
总结:整理一下上述流程,当调用getResponseWithInterceptorChain()
方法后,初始化拦截器和链条,并为链条添加5
个节点,后续调用链条的proceed()
方法,proceed()
会去创建一个新链条,并使下标加1
,再执行当前链条的下标位置的拦截器的intercept()
方法,并将刚才创建的链条当成参数传入intercept()
方法,在拦截器的intercept()
方法实现中,又会递归去调用传入链条的proceed()
方法,直到链条执行结束。
经过上述分析,拦截器的职责也就显而易见了,重点是intercept()
,以Response
的返回作为分界,
- 上部分:封装
Request
- 分界线:向下层传递
Requset
,并返回Response
- 下部分:处理返回的
Response
✨ 原 创 不 易 , 还 希 望 各 位 大 佬 支 持 一 下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下
👍 点 赞 , 你 的 认 可 是 我 创 作 的 动 力 ! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!
⭐️ 收 藏 , 你 的 青 睐 是 我 努 力 的 方 向 ! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!
✏️ 评 论 , 你 的 意 见 是 我 进 步 的 财 富 ! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!
下篇预告:分析第一个拦截器-RetryAndFollowUpInterceptor
,分析其如何重试和重定向