### 前言
回顾:
[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

Okhttp3源码解析(4)-拦截器与设计模式的更多相关文章

  1. Okhttp3源码解析(5)-拦截器RetryAndFollowUpInterceptor

    ### 前言 回顾: [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析](htt ...

  2. 源码解析Grpc拦截器(C#版本)

    前言 其实Grpc拦截器是我以前研究过,但是我看网上相关C#版本的源码解析相对少一点,所以笔者借这篇文章给大家分享下Grpc拦截器的实现,废话不多说,直接开讲(Grpc的源码看着很方便,包自动都能还原 ...

  3. axios源码解析 - 请求拦截器

    axios请求拦截器,也就是在请求发送之前执行自定义的函数. axios源码版本 - ^0.27.2 (源码是精简版) 平时在业务中会这样去写请求拦截器,代码如下: // 创建一个新的实例 var s ...

  4. axios 源码解析(下) 拦截器的详解

    axios的除了初始化配置外,其它有用的应该就是拦截器了,拦截器分为请求拦截器和响应拦截器两种: 请求拦截器    ;在请求发送前进行一些操作,例如在每个请求体里加上token,统一做了处理如果以后要 ...

  5. Okhttp3源码解析(3)-Call分析(整体流程)

    ### 前言 前面我们讲了 [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析]( ...

  6. springMVC源码分析之拦截器

    一个东西用久了,自然就会从仅使用的层面上升到探究其原理的层面,在javaweb中springmvc更是如此,越是优秀的框架,其底层实现代码更是复杂,而在我看来,一个优秀程序猿就相当于一名武林高手,不断 ...

  7. springMVC源码分析--HandlerInterceptor拦截器调用过程(二)

    在上一篇博客springMVC源码分析--HandlerInterceptor拦截器(一)中我们介绍了HandlerInterceptor拦截器相关的内容,了解到了HandlerInterceptor ...

  8. Okhttp3源码解析(2)-Request分析

    ### 前言 前面我们讲了 [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析]( ...

  9. SpringMVC源码阅读:拦截器

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

随机推荐

  1. TCP协议传输大文件读取时候的问题

    TCP协议传输大文件读取时候的问题 大文件传不完的bug 我们在定义的时候定义服务端每次文件读取大小为10240, 客户端每次接受大小为10240 我们想当然的认为客户端每次读取大小就是10240而把 ...

  2. python执行unittest界面设置

    执行单元测试时,系统会自动添加unittest in...的执行服务器. 执行时unittest in...的执行服务器在界面右上方可以看到,且执行结果为左侧框和右侧统计结果. 如果没有,会导致测试结 ...

  3. 小白学python-day04-运算符、while循环相关

    今天是day04.以下是学习总结. 但行努力,莫问前程. ----------------------------------------------------------------------- ...

  4. python找质数对

    python找质数对 编写python脚本,输入一个正整数,输出有几对质数的和等于这个正整数. 例如输入一个正整数10,可以找出有“3+7=10”.“5+5=10”两个质数对的和为10. 要实现这个功 ...

  5. python基础——字典(dict)

    字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中 . dict1 = {} ...

  6. sass的核心知识及使用

    sass的官方链接地址:htpp://sass-lang.com 参考链接地址:http://www.haorooms.com/post/sass_css 1. 基础语法 1.1 变量 SASS允许使 ...

  7. UIRefreshControl 问题

    这两天在学UIRefreshControl,主要参照的是github上的一个Demo(网址 https://github.com/evgeniymikholap/UIRefreshControlExa ...

  8. 整理github总结

    之前记述过两篇关于git命令的随笔,那时候对git的理解还不太深(虽然现在理解的也不是很多...菜哭了),只会用那些命令,并没有形成自己的知识,今天下载完Git之后,规整了一下自己的github,在吃 ...

  9. 机房ping监控 smokeping+prometheus+grafana(续) 自动获取各省省会可用IP

    一.前言 1.之前的文章中介绍了如何使用smokeping监控全国各省的网络情况:https://www.cnblogs.com/MrVolleyball/p/10062231.html 2.由于之前 ...

  10. zmnXAglTcg

    #include <map>#include <cmath>#include <stack>#include <queue>#include <l ...