欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Okhttp3源码解析(4)-拦截器与设计模式

程序员文章站 2023-08-23 10:19:09
### 前言 回顾: [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析](https://www.jianshu.com/p/bf1d01b79ce7) [Okhttp3源码解析( ......
### 前言 回顾: [okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [okhttp3源码解析(1)-okhttpclient分析](https://www.jianshu.com/p/bf1d01b79ce7) [okhttp3源码解析(2)-request分析](https://www.jianshu.com/p/5a85345c8ea7) [okhttp3源码解析(3)-call分析(整体流程)](https://www.jianshu.com/p/4ed79472797a) 上节我们讲了okhttp的整体的流程,里面的核心方法之一是`getresponsewithinterceptorchain()` ,这个方法应该知道吧?通过拦截器层层处理返回response;这个方法中其实应用了责任链设计模式。今天主要讲一下它是如何应用的! ### 责任链设计模式 ###### 责任链模式的定义 在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。 模型: ![](https://img2018.cnblogs.com/blog/1312938/201908/1312938-20190827082427829-283762395.png) 1.优点 耦合度降低,请求和处理是分开的 2.缺点 责任链太长或者每条链判断处理的时间太长会影响性能。特别是递归循环的时候 不一定被处理,每个职责类的职责很明确,这就需要对写默认的处理了 **责任链模式重要的两点:分离职责,动态组合** 对责任链设计模式不明白的可以去网上那个找找实例看看, 这里就不举例子了。 ### 源码中的责任链 话不多说,直接上`getresponsewithinterceptorchain()` 源码 ``` response getresponsewithinterceptorchain() throws ioexception { // build a full stack of interceptors. list interceptors = new arraylist(); interceptors.addall(client.interceptors()); //自定义 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, this, eventlistener, client.connecttimeoutmillis(), client.readtimeoutmillis(), client.writetimeoutmillis()); return chain.proceed(originalrequest); } ``` 方法中大部分上节已经说了,就是 `list`添加自定义、cookie等等的拦截器,今天我们主要看看后半部分: ``` interceptor.chain chain = new realinterceptorchain(interceptors, null, null, null, 0, originalrequest, this, eventlistener, client.connecttimeoutmillis(), client.readtimeoutmillis(), client.writetimeoutmillis()); return chain.proceed(originalrequest); ``` 首先初始化了 `realinterceptorchain`,`realinterceptorchain`是`interceptor.chain`的实现类 ![](https://img2018.cnblogs.com/blog/1312938/201908/1312938-20190827082428677-935973782.png) 先看一下`interceptor.chain`: ``` public interface interceptor { response intercept(chain chain) throws ioexception; interface chain { request request(); response proceed(request request) throws ioexception; //部分代码省略.... } } ``` 生成了realinterceptorchain的实例,调用了`proceed()`,返回了最后的response 我们看下 `realinterceptorchain`类中的`proceed()`: ``` @override public response proceed(request request) throws ioexception { return proceed(request, streamallocation, httpcodec, connection); } 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, call, eventlistener, connecttimeout, readtimeout, writetimeout); 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