前面分析了请求的具体执行流程,请求最终会经过一个由多个拦截器组成的链条来处理具体的请求和响应,这个便是我们熟知的调用链(责任链)模式
责任链模式
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。如图所示:

上图形象地描述了责任链模式的工作状态,这里就不具体展开介绍了,如需进一步了解,可参考相关资料。
拦截器链
在OkHttp中,责任链中的处理器是各种拦截器,除了自身提供的5个核心拦截器外,它还允许使用者自定义拦截器,并加入其拦截器链链中。先来看看这条“链”的接口定义:
interface Chain { //返回请求对象 Request request(); //执行具体的请求,并获取响应 Response proceed(Request request) throws IOException; //返回连接 Connection connection(); } 复制代码
其中proceed的方法很重要,它定义输入请求,输出响应,具体的实现子类来执行。RealInterceptorChain是其实现的子类,其proceed的方法实现如下:
@Override public Response proceed(Request request) throws IOException { return proceed(request, streamAllocation, httpCodec, connection); } 复制代码
拦截器链的运行方式
RealInterceptorChain实现的proceed方法调用了自己的proceed的方法,这个方法是拦截器链模式的实现,它定义了我们我们的请求是如何经过层层拦截器处理,获取响应的过程,实现细节参考下面的代码:
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException { if (index >= interceptors.size()) throw new AssertionError(); calls++; // If we already have a stream, confirm that the incoming request will use it. if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) { throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) + " must retain the same host and port"); } // If we already have a stream, confirm that this is the only call to chain.proceed(). if (this.httpCodec != null && calls > 1) { throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) + " must call proceed() exactly once"); } // Call the next interceptor in the chain. RealInterceptorChain next = new RealInterceptorChain( interceptors, streamAllocation, httpCodec, connection, index + 1, request); Interceptor interceptor = interceptors.get(index); Response response = interceptor.intercept(next); // Confirm that the next interceptor made its required call to chain.proceed(). if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) { throw new IllegalStateException("network interceptor " + interceptor + " must call proceed() exactly once"); } // Confirm that the intercepted response isn't null. if (response == null) { throw new NullPointerException("interceptor " + interceptor + " returned null"); } return response; } 复制代码
从上面的代码中提炼了三句最最核心的代码:
// Call the next interceptor in the chain.
//每次调用取出下一个拦截器,index = index+1就表示下一个拦截器的索引
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
//取出要处理的拦截器
Interceptor interceptor = interceptors.get(index);
//调用每个拦截器的intercept方法,每个拦截器中都要调用chain的proceed方法,这样就是相当于把请求传递到下一个拦截器处理
Response response = interceptor.intercept(next);
复制代码
这三句代码实现了请求在不同拦截器间的处理和向下传递。上面代码中有几个关键的参数: interceptors:拦截器集合,所有的拦截器都存储于此集合中; index:拦截器的索引,用于表示当前处理到的拦截器在interceptors列表中的索引位置; 在实现自定义拦截器的时候,一定不要忘了调用的chain的proceed方法,否则链条就要断裂。
“链条”的创建
了解了okhttp中拦截器链的运行方式,来看看这个链条是怎么创建的,以及框架默认创建了哪些拦截器。回到RealCall对象中,请求的发起是通过getResponseWithInterceptorChain实现的,参考代码如下:
Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. List<Interceptor> interceptors = new ArrayList<>(); //添加用户创建的拦截器到拦截器链中,并先于系统默认的拦截器之前执行 interceptors.addAll(client.interceptors()); //用于错误恢复和重定向跟踪,创建了后面要使用的StreamAllocation类 interceptors.add(retryAndFollowUpInterceptor); //此类用于预处理请求和响应,如默认添加许多请求头和解析响应头 interceptors.add(new BridgeInterceptor(client.cookieJar())); //根据需要是否从缓存中返回响应 interceptors.add(new CacheInterceptor(client.internalCache())); //创建请求端连接 interceptors.add(new ConnectInterceptor(client)); if (!forWebSocket) { interceptors.addAll(client.networkInterceptors()); } //完成请求体和请求体数据的传输,并获取响应数据 interceptors.add(new CallServerInterceptor(forWebSocket)); //创建拦截器链 Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest); //通过拦截器执行具体的请求 return chain.proceed(originalRequest); } 复制代码
此方法中创建了默认的几个核心拦截器,并加入到interceptors集合中,接着创建Chain,并调用了proceed方法,由此开始了请求的处理。
原文
https://juejin.im/post/5d463ef9e51d45621320309e
本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » OkHttp(三) – 拦截器链处理过程分析