责任链模式的概念
责任链模式定义如下:
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.Chain the receiving objects and pass the request along the chain until an object handles it.(翻一下:使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理为止。)
用简单的类图表示如下:
文章图片
从概念上和类图上可以推断责任链会带来最大的优点,就是将请求和处理分开,请求者完全不用care是谁处理,是谁在加工。模式的核心在于创建一条chain,而处理具体事务的是chain的节点ConcreteHandler。研究这个模式,okhttp的拦截器机制是很好的研究点。
OKhttp的拦截器机制
这里展示一下demo,简单输出一下url,demo只是为了演示用法,不具有实际应用性。
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(hostSelectionInterceptor)
.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
System.out.println("request url intercept " + request.url().toString());
return chain.proceed(request);
}
})
.build();
Request request = new Request.Builder().url("http://www.github.com/").build();
Response response = okHttpClient.newCall(request).execute();
控制台会打印:“request url intercept http://www.github.com/”,request和interceptor解耦,request不用care intercept 怎么处理,只关心repose的内容。
这个具体实现原理到底是啥呢,这里不扒okhttp的运行原理,只讲重点部分。
OkhttpClient.newCall(request)返回的对象的类是RealCall,我们直接看这个类的execute方法,
public Response execute() throws IOException {
synchronized(this) {
if (this.executed) {
throw new IllegalStateException("Already Executed");
}this.executed = true;
}this.transmitter.timeoutEnter();
this.transmitter.callStart();
Response var1;
try {
this.client.dispatcher().executed(this);
var1 = this.getResponseWithInterceptorChain();
} finally {
this.client.dispatcher().finished(this);
}return var1;
}
关键看this.getResponseWithInterceptorChain(),在这个方法里处理了拦截器机制的主要逻辑。
Response getResponseWithInterceptorChain() throws IOException {
List interceptors = new ArrayList();
interceptors.addAll(this.client.interceptors());
interceptors.add(new RetryAndFollowUpInterceptor(this.client));
interceptors.add(new BridgeInterceptor(this.client.cookieJar()));
interceptors.add(new CacheInterceptor(this.client.internalCache()));
interceptors.add(new ConnectInterceptor(this.client));
if (!this.forWebSocket) {
interceptors.addAll(this.client.networkInterceptors());
}interceptors.add(new CallServerInterceptor(this.forWebSocket));
Chain chain = new RealInterceptorChain(interceptors, this.transmitter, (Exchange)null, 0, this.originalRequest, this, this.client.connectTimeoutMillis(), this.client.readTimeoutMillis(), this.client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
Response var5;
try {
Response response = chain.proceed(this.originalRequest);
if (this.transmitter.isCanceled()) {
Util.closeQuietly(response);
throw new IOException("Canceled");
}var5 = response;
} catch (IOException var9) {
calledNoMoreExchanges = true;
throw this.transmitter.noMoreExchanges(var9);
} finally {
if (!calledNoMoreExchanges) {
this.transmitter.noMoreExchanges((IOException)null);
}}return var5;
}
先创建了拦截器的数组interceptors,this.client.interceptors()返回的是我们自己定义的拦截器,经常使用的还有处理cookie的BridgeInterceptor,其他都是框架内置的拦截器。然后创建了链对象chain,类型是RealInterceptorChain,RealInterceptorChain的构造方法:
public RealInterceptorChain(List interceptors, Transmitter transmitter, @Nullable Exchange exchange, int index, Request request, Call call, int connectTimeout, int readTimeout, int writeTimeout) {
this.interceptors = interceptors;
this.transmitter = transmitter;
this.exchange = exchange;
this.index = index;
this.request = request;
this.call = call;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
}
chain保存interceptors数组,其他参数如transmitter,exchange 暂且不提,这里主要理解责任链模式。这个数组其实就是所以处理具体事务的节点。
【Android|责任链模式应用之Okhttp的拦截器机制】最后调用chain.proceed方法。
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange) throws IOException {
if (this.index >= this.interceptors.size()) {
throw new AssertionError();
} else {
++this.calls;
if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + this.interceptors.get(this.index - 1) + " must retain the same host and port");
} else if (this.exchange != null && this.calls > 1) {
throw new IllegalStateException("network interceptor " + this.interceptors.get(this.index - 1) + " must call proceed() exactly once");
} else {
RealInterceptorChain next = new RealInterceptorChain(this.interceptors, transmitter, exchange, this.index + 1, request, this.call, this.connectTimeout, this.readTimeout, this.writeTimeout);
Interceptor interceptor = (Interceptor)this.interceptors.get(this.index);
Response response = interceptor.intercept(next);
if (exchange != null && this.index + 1 < this.interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor + " must call proceed() exactly once");
} else if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
} else if (response.body() == null) {
throw new IllegalStateException("interceptor " + interceptor + " returned a response with no body");
} else {
return response;
}
}
}
}
传入request,还记得前面构造RealInterceptorChain对象,exchange对象是null,所以在proceed方法中,逻辑会走到else分支,就是获取下一个拦截器(下一个节点)来处理这个请求,调用拦截器的interceptos方法,传入新创建的节点。这里和标准的责任链不一样,第一个是节点处理顺序是用数组元素的顺序,第二个不同点每次调用下一个节点的时候,是重新创建的,没有一开始就把链创建好,但其思想是一样的,如果调用的是execute,那么拦截器的执行就在调用的线程,如果是enqueue,那么是在线程池创建的线程里,这个不详细说明,可以看源码,okhttp的执行流程还是很清晰的。最后返回的是response对象。此时我们可以画一个简单的类图。
文章图片
在这里拦截器起这么一个作用,执行下一个节点的proceed方法或者直接返回响应的response,在执行前后给request或者response加工。在okhttp中直接返回response的拦截器就是CallServerInterceptor,可以看下这个拦截器的proceed方法,就是最终处理了request。下一篇文章实战下,分析下自带的BridgeInterceptor将cookie添加到request中。
总结
okhttp的拦截器机制是通过责任链模式来设计,虽然不是标准的责任链,但实现这个模式的主要思想。RealCall发起了请求,拦截器处理请求并调用下一个节点的处理,形成一条完美的chain,最后返回请求结果response