拦截器的实现使用了责任链模式,了解一下责任链模式对理解起来有帮助。
本文注意分析拦截器的“链”如何形成、开始和结束。
1. 介绍
拦截器,可以拦截请求和响应,对数据进行监视或者修改。拦截器使用双链责任链,先添加的拦截器最先拦截请求,最后拦截响应。拦截器分为网络拦截器和应用拦截器,一般添加的都是应用拦截器。
2. 使用
- 添加依赖
api 'com.squareup.okhttp3:okhttp:3.14.9'
4.0及以上内部实现为kotlin,这里分析3.14.9版本,不同版本源码会有差异。
- 自定义拦截器
/**
* Copyright © www.zingking.cn
*
* 自定义拦截器
*/
class CustomInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
// deal request ...
val response = chain.proceed(chain.request())
// deal response ...
return response
}
}
- 创建请求
// 示例类
class xx{
// 实例方法
fun request(){
val url = "http://www.baidu.com"
val okHttpClient = OkHttpClient().newBuilder()
// 添加拦截器
.addInterceptor(CustomInterceptor())
.build()
val request: Request = Request.Builder()
.url(url)
.build()
val call: Call = okHttpClient.newCall(request)
// 同步请求
var response: Response = call.execute()
// 或者异步请求
call.enqueue(object :Callback{
override fun onFailure(call: Call, e: IOException) {
}
override fun onResponse(call: Call, response: Response) {
}
})
}
}
3. 分析
基于com.squareup.okhttp3:okhttp:3.14.9
根据前面的介绍,思考几个问题:
- okhttp内部有没有默认拦截器?有什么作用?
- 自定义添加的拦截器和内部拦截器的优先级如何?
- 如何替换okhttp内部网络请求?
3.1 拦截器的相关类
拦截器涉及到的相关类不仅仅是为拦截器服务,这里只会着重介绍和拦截器相关的代码。
看一下类图:
类图展示了与拦截器相关的关键关系,其余关系再加上去会很混乱,例如:RealInterceptorChain
实际上持有Request和Call成员变量,与其2个是关联关系。第一行是网络请求参数和结果,第二行是执行的请求、拦截器、“链”接口,第三行是接口的实现类和OkHttpClient。
Request
“链”中持有的请求参数,也是责任链模式双链中的第1条链,拦截请求的关键参数。
Response
“链”中处理后的响应参数,也是责任链模式双链中的第2条链,拦截响应的关键参数。
Call和RealCall
一个Call是一个已准备执行的请求,内部有同步执行和异步执行。 而RealCall
是Call接口的唯一(final)实现类,内部持有了OkHttpClient
和Request
,也是责任链开始的地方。
Interceptor
拦截器接口,内部只有一个拦截方法,其实现类是属于链中的某一个具体的处理对象;自定义拦截器实现该方法可以处理请求参数和响应结果。
Chain和RealInterceptorChain
“链”接口,是Interceptor
内部类接口,内部有比较多的接口方法,这里只关心和拦截器相关的。“链”用来串联起具体的处理对象并携带有请求参数,管理调用顺序。在责任链模式中,一般处理方法和传递方法都是同一个(例如:handleRequest)。拦截器的实现把这两个方法分开了,处理方法是Interceptor.intercept(...)
,传递方法是Interceptor.Chain.proceed(...)
。
RealInterceptorChain
是Chain接口的唯一(final)实现类,内部持有所有的拦截器集合,和当前链应该处理的拦截器索引。在实际传递和拦截过程中也创建的该对象。
OkHttpClient
okhttp的客户端类,功能很多,这里只关心和拦截器相关的。内部维护了2个拦截器集合,一个是普通拦截器,一个是网络拦截器。2个集合会在请求时被添加到RealInterceptorChain
中的集合里一起传递。
3.2 源码
Request
和Response
在拦截器中作为链传递时携带的数据,内部源码都是一些请求参数和响应结果,这里不会再分析源码。
- Chain是Interceptor的内部类接口,Chain目前只有一个唯一的实现类RealInterceptorChain且是
final
的,来看一下这三个的源码:
// 抽象的处理者,其实现类是属于链中的某一个具体的处理对象
public interface Interceptor {
// 处理方法,由具体处理者实现该方法,处理自己对应的业务逻辑
Response intercept(Chain chain) throws IOException;
interface Chain {
// 得到链中传递的请求参数
Request request();
// 传递方法,将请求传递给下一个处理对象
Response proceed(Request request) throws IOException;
// 返回请求将被执行的连接。 这个方法仅在网络拦截器中使用,音乐拦截器返回永远是空
@Nullable Connection connection();
...
}
}
Interceptor是拦截器,自定义的拦截器中实现intercept方法,可以拿到“链”对象并对其请求进行处理,接着可以调用“链”对象的proceed方法,将请求传递到下一个拦截器。如果不调用proceed方法,后面的拦截器也就不会再处理。这样一直传递到最后一个拦截器,返回Response实例。接着看一下拦截链的源码:
// 承载整个拦截链的具体拦截链
public final class RealInterceptorChain implements Interceptor.Chain {
// 所有拦截器集合,包含内部默认和自定义添加的
private final List interceptors;
// 当前链中对应的拦截器索引
private final int index;
// 网络请求参数,但是在链传递过程中的请求参数不是这个
private final Request request;
// 构造函数,给成员变量赋值
public RealInterceptorChain(List interceptors, Transmitter transmitter,
@Nullable Exchange exchange, int index, Request request, Call call,
int connectTimeout, int readTimeout, int writeTimeout) {
this.xx = xx;
}
// 实现接口方法,返回网络请求
@Override
public Request request() {
return request;
}
// 实现接口方法
@Override
public Response proceed(Request request) throws IOException {
return proceed(request, transmitter, exchange);
}
// 负责将请求传递到下一个拦截器
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange) throws IOException {
// 省略一些参数校验...
// 调用链中的下一个拦截器
// RealInterceptorChain 第 1 4 5 个参数分别为:
// interceptors:包含所有拦截器的集合;index + 1:下一个链中对应的拦截器索引;request:请求参数
// 注意:request是局部变量,即入参的requset,不是成员变量;保证了每次拦截对request的修改都有效
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
// 获取当前链对应的拦截器
Interceptor interceptor = interceptors.get(index);
// 调用当前链的拦截方法,注意参数是下一个链,可以理解为在下一个链之前拦截
Response response = interceptor.intercept(next);
// 省略一些合法性校验...
return response;
}
}
关键方法proceed(...),创建了一个新的RealInterceptorChain实例作为下一个拦截链,并调用当前拦截器的拦截方法;例如当index为0时,当前链实例的所有成员变量(request等)都是"0版本",故新的RealInterceptorChain实例持有的成员变量在调用interceptor.intercept(next)
之前都是“0版本”,只有索引指向了下一个拦截器;在实现interceptor时,可以对链实例的成员变量进行操作,而操作后的成员变量可以理解为“1版本”,此时index(等于1)和成员变量版本一一对应。
即“0版本成员变量”和“1索引”作为参数封装到一起传递给第0个拦截器处理,在第0个拦截器处理后“0版本成员变量”发生了变化即与“1索引”一一对应了。
- OkHttpClient在拦截器中的作用就比较简单,维护了2个拦截器集合用于暂存自定义的拦截器,请求开始时会被整体添加到RealInterceptorChain中的集合里:
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
// 应用拦截器
final List interceptors;
// 网络拦截器
final List networkInterceptors;
// 返回应用拦截器
public List interceptors() {
return interceptors;
}
// 返回网络拦截器
public List networkInterceptors() {
return networkInterceptors;
}
// 接收一个请求参数,创建一个Call
@Override
public Call newCall(Request request) {
// 调用RealCall静态方法,第三个参数为false
return RealCall.newRealCall(this, request, false);
}
// 通过builder链式调用创建OkHttpClient实例
public static final class Builder{
...
}
}
- Call和RealCall,RealCall作为Call的实现类,是请求的开始固然也是拦截器开始:
public interface Call extends Cloneable {
// 返回发起此调用的原始请求。
Request request();
// 同步执行请求
Response execute() throws IOException;
// 异步执行请求
void enqueue(Callback responseCallback);
}
final class RealCall implements Call {
// OkHttpClient实例
final OkHttpClient client;
// 原始请求
final Request originalRequest;
// 是否是针对webSocket
final boolean forWebSocket;
// 构造函数给成员变量赋值
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
}
// 静态方法创建Call
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.transmitter = new Transmitter(client, call);
return call;
}
// 返回原始请求
@Override public Request request() {
return originalRequest;
}
// 同步执行
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.timeoutEnter();
transmitter.callStart();
try {
client.dispatcher().executed(this);
// * 调用内部方法获取响应结果
return getResponseWithInterceptorChain();
} finally {
client.dispatcher().finished(this);
}
}
// 异步执行
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
// 将回调添加到一个runnable中
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
// 异步执行的Runnable
final class AsyncCall extends NamedRunnable {
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
// 异步执行时会调度到这里
@Override
protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
// * 调用内部方法获取响应结果
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
} catch (IOException e) {
if (signalledCallback) {
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} catch (Throwable t) {
cancel();
if (!signalledCallback) {
IOException canceledException = new IOException("canceled due to " + t);
canceledException.addSuppressed(t);
responseCallback.onFailure(RealCall.this, canceledException);
}
throw t;
} finally {
client.dispatcher().finished(this);
}
}
}
}
通过上面的分析可以看出,无论是同步还是异步,最后都会执行到getResponseWithInterceptorChain()
这个方法来获取响应结果:
final class RealCall implements Call {
// 获取响应结果
Response getResponseWithInterceptorChain() throws IOException {
// 构建一个完整的拦截器列表,即包含了内部默认和自定义
List interceptors = new ArrayList<>();
// 添加client携带的应用拦截件集合
interceptors.addAll(client.interceptors());
// 添加4个内部默认的拦截器
interceptors.add(new RetryAndFollowUpInterceptor(client));
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
// 添加client携带的网络拦截件集合
interceptors.addAll(client.networkInterceptors());
}
// 添加最后一个调用网络服务的拦截器,最终的网络请求就是在这里
interceptors.add(new CallServerInterceptor(forWebSocket));
// 创建第1个拦截链,重要参数包含:所有拦截器interceptors;索引 0 ;请求参数originalRequest;
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
// 开始执行第0个拦截链;注意这里不是interceptor.intercept(chain);
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
}
通过上面的分析很容易了解:
- 内部有5个拦截器
- 自定义应用拦截器优先级最高;发生网络请求的拦截器优先级最低,自定义网络拦截器次之;中间是默认的一些配置、功能性拦截器
- 若在自定义拦截器中直接返回结果,而不是调用chain.proceed(...)即可替换内部网络请求
4. 总结
- 拦截器使用责任链双链模式
- 自定义应用拦截器优先级最高
- 先添加的拦截器最先拦截请求,最后拦截结果(责任链的特性)