Android|责任链模式应用之Okhttp的拦截器机制

责任链模式的概念
责任链模式定义如下:
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.(翻一下:使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理为止。)
用简单的类图表示如下:
Android|责任链模式应用之Okhttp的拦截器机制
文章图片

从概念上和类图上可以推断责任链会带来最大的优点,就是将请求和处理分开,请求者完全不用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对象。此时我们可以画一个简单的类图。
Android|责任链模式应用之Okhttp的拦截器机制
文章图片

在这里拦截器起这么一个作用,执行下一个节点的proceed方法或者直接返回响应的response,在执行前后给request或者response加工。在okhttp中直接返回response的拦截器就是CallServerInterceptor,可以看下这个拦截器的proceed方法,就是最终处理了request。下一篇文章实战下,分析下自带的BridgeInterceptor将cookie添加到request中。
总结
okhttp的拦截器机制是通过责任链模式来设计,虽然不是标准的责任链,但实现这个模式的主要思想。RealCall发起了请求,拦截器处理请求并调用下一个节点的处理,形成一条完美的chain,最后返回请求结果response

    推荐阅读