责任链
Chain of Responsibility
将多个不同职责的处理者连接为一条链,一个请求沿着这条链进行发送,每个处理者都可以对请求进行处理,处理完成后丢弃或者传递给链中的下一个处理者;
在 OkHttp的拦截器中,就是采用了责任链模式,而且请求沿着责任链处理后,发送得到响应后,还会沿着 责任链的反方向 继续处理;
什么时候使用呢?
当需要使用不同的方式处理不同种类的请求时;
当需要按某种顺序(这个顺序可以是动态的)执行多个处理者时;
责任链的实现基本可以分为两种:
一种是单向传递:可以使用单链表或者数组来实现;
另一个是双向传递(从左到右,从右到左):可以使用 递归 去实现
无论哪种实现,实际上都是对一系列不同处理的分层处理;
单向传递的责任链
责任链中的所有处理对象都应该实现同一个接口:
// 这里使用 Kotlin 的函数式接口,方便编写不同的处理者
fun interface Processor {
fun process(req: Request): Boolean
}这个 process 函数的返回值根据实际需求定义:
如果是检查某些条件是否合适,那么可以返回 Boolean 来表示检查是否通过;
如果是会根据传入的参数构建新的实例,那么可以返回对应的实例类型,以表示是否需要覆盖原本的值
// 这个 Request 可以是创建新的实例,也可以是没有创建前的实例 fun process(req: Request): Request
使用数组
使用数组来对所有责任链上的处理者调用;
class Request {
var name: String? = null
var header: String? = null
override fun toString(): String {
return "Request(name: $name, header: $header)"
}
}
fun main() {
val processors = mutableListOf(
Processor {
// 起个名字
it.name = "processor1"
println("processor1 handle")
true
},
Processor {
// 加个请求头
it.header = "processor2"
println("processor2 handle")
true
},
)
val req = Request()
for (processor in processors) {
val state = processor.process(req)
if(!state) {
break // or throw Exception
}
}
println(req)
}
/*
运行结果:
processor1 handle
processor2 handle
Request(name: processor1, header: processor2)
*/使用单链表
通过给拦截器加上指向下一个拦截器的字段来实现
同样也是相同的迭代,只是改成了单链表的迭代方式;
此处不再赘述
双向传递的责任链
从左到右传递请求,得到结果后,从右到左传递结果;
通常会使用 递归 去实现
声明一个 Request 和 Response
class Request {
var name: String? = null
var header: String? = null
override fun toString(): String {
return "Request(name: $name, header: $header)"
}
}
class Response {
var name: String? = null
var req: Request? = null
var header: String? = null
override fun toString(): String {
return "Request(name: $name, header: $header, req: $req)"
}
}如果按照上面单向迭代的方式,可能会想到这种责任链处理者的接口;
// 错误的
fun interface Processor {
fun process(req: Request): Response
}有多个拦截器,但是每个拦截器都需要 Request 参数,而第一个拦截器返回了 Response,那下一个拿什么传进入?
此时这种类似数组的迭代方式就无法满足现在的需求了;
也就是说,需要用另外一些东西去充当处理者之间的 “桥梁”:
维护当前传递到责任链的哪个部分?
将 Request 传递给责任链下一个处理者
将 Response 返回给责任链的前一个处理者
class Chain(
val processors: List<Processor>, // 责任链链
val processIndex: Int,
val request: Request
) {
// 核心方法
fun deliver(req: Request): Response {
// 当前处理的拦截器
val processor = processors[processIndex]
// 下一个桥梁:也是指定了下一个交给责任链的位置
val nextChain = Chain(processors, processIndex + 1, req)
// 当前处理者返回的结果
val response = processor.process(nextChain)
return response
}
}接下来的处理者实现:
fun main() {
val processors = mutableListOf(
Processor { chain ->
chain.request.name = "processor1"
println("processor1 handle request ${chain.request}")
// 拿到的是 Processor2 的结果
val response = chain.deliver(chain.request)
println("processor1 handle response $response")
response.apply {
name = "processor1"
}
},
Processor { chain ->
chain.request.header = "processor2"
println("processor2 handle request ${chain.request}")
// 拿到的是 Processor3 的结果
val response = chain.deliver(chain.request)
println("processor2 handle response $response")
response.apply {
header = "processor2"
}
},
Processor { chain ->
println("process3 handle and return response")
Response().apply { req = chain.request }
}
)
val request = Request()
val chain = Chain(processors, 0, request)
val response = chain.deliver(request)
println("completed handle $response")
}
/*
运行结果
processor1 handle request Request(name: processor1, header: null)
processor2 handle request Request(name: processor1, header: processor2)
process3 handle and return response
processor2 handle response Request(name: null, header: null, req: Request(name: processor1, header: processor2))
processor1 handle response Request(name: null, header: processor2, req: Request(name: processor1, header: processor2))
completed handle Request(name: processor1, header: processor2, req: Request(name: processor1, header: processor2))
*/从上面的例子中,可以看到这就是一个递归的过程,以 Processor3 作为递归的终点(不继续向下传递而是直接返回)
OkHttp责任链实现(源码)
OkHttp的拦截器接口 Interceptor 中同时还包含了 Chain 接口的声明:
Interceptor是一个函数式接口:fun interface Interceptor { @Throws(IOException::class) fun intercept(chain: Chain): Response // omit.. }该
intercept就是拦截器的核心处理方法内部声明了
Chain接口:interface Chain { @Throws(IOException::class) fun proceed(request: Request): Response // 省略其他方法 }该
process方法就是沿着责任链向下传递的关键
getResponseWithInterceptorChain
RealCall 也就是封装的网络请求类中, getResponseWithInterceptorChain 方法是将请求发送出去,经过拦截链后拿到响应结果;
拦截链的设置也是在此处完成的,从左到右分别是
OkHttpClient设置的自定义拦截器
重定向拦截器
RetryAndFollowUpInterceptor桥拦截器
RetryAndFollowUpInterceptor:负责给请求添加所需的请求头,以及根据需要给拿到的响应进行解压;缓存拦截器
CacheInterceptor:负责HTTP缓存的处理;连接拦截器
ConnectInterceptor:负责建立与目标服务器的连接;发送请求拦截器:
CallServerInterceptor最后一个拦截器,将请求发送出去;
// RealCall#getResponseWithInterceptorChain
val interceptors = mutableListOf<Interceptor>()
// OkHttpClient 构建时的应用
interceptors += client.interceptors
interceptors += RetryAndFollowUpInterceptor(client)
interceptors += BridgeInterceptor(client.cookieJar)
interceptors += CacheInterceptor(client.cache)
interceptors += ConnectInterceptor
if (!forWebSocket) {
interceptors += client.networkInterceptors
}
interceptors += CallServerInterceptor(forWebSocket)什么时候将请求传入?
// RealCall#getResponseWithInterceptorChain
val chain = RealInterceptorChain(
call = this,
interceptors = interceptors,
index = 0,
exchange = null,
request = originalRequest, // 需要发送的请求
connectTimeoutMillis = client.connectTimeoutMillis,
readTimeoutMillis = client.readTimeoutMillis,
writeTimeoutMillis = client.writeTimeoutMillis
)
...
// 传入拦截器链,开始处理这个请求;
val response = chain.proceed(originalRequest)究竟是怎么实现 Request 经过拦截器链处理后发送得到响应还能经过拦截器回来的呢?
多个拦截器的一去一回,不难联想到递归;
所有的拦截器,接收
Chain,相当于拿到Request,通过Chain.proceed拿到对应的Response那递归总得有一个起点和终点吧:上面的
chain.proceed就是启动,而终点自然就是拦截链的最后一个拦截器CallServerInterceptor
拦截链起点
RealInterceptorChain 是拦截链的起点,也是沿着拦截链传递的“驱动”;
内部保存了一整个拦截链 interceptors,当前请求在拦截器的位置 index;
从上面实例化看到其 index 的初始值为 0,也就是说从第一个拦截器开始调用;
override fun proceed(request: Request): Response {
check(index < interceptors.size)
...
// Call the next interceptor in the chain.
val next = copy(index = index + 1, request = request)
val interceptor = interceptors[index]
val response = interceptor.intercept(next) ?: throw NullPointerException(
"interceptor $interceptor returned null")
...
return response
}递归调用,每次调用 intercept 时都会指定下一个拦截器的位置 index + 1,
在拦截器的 intercept 方法中会调用 chain.proceed(request) 即回到这处代码重复执行;
拦截链终点
处于拦截链的最后一个拦截器 CallServerInterceptor,负责将请求发送出去,并接收其响应;
在其 intercept 方法,并没有调用 Chain.proceed 继续往下传递(因为已经是最后一个了);
此时获取响应并进行一次处理后,就会返回 Response 对象;
(此时就是递归过程中的 “归”)
总结
为什么要用一个 RealInterceptorChain, 而不是直接遍历两次 interceptors ?
在 RealInterceptorChain 内部有对某些情况的处理,单独封装;
Interceptor 的拦截逻辑可能涉及到 Request 和 Response 的信息,使用 RealInterceptorChain 来传递请求和响应能保证对 Request 和 Response 的访问是同一次调用
Intercetpor 能够提前返回 Response ,比如 CacheInterceptor提前返回缓存的响应数据;如果使用两次遍历无法处理这种情况,这些情况适合 递归 去实现;
RealInterceptorChain 承载了整个拦截链,并驱动其运行;