系列文章
OkHttp学习(一) OSI七层模型和TCP四层模型
OkHttp学习(二) 3.10.0版本的简单使用及其流程梳理
OkHttp学习(三) 3.10.0版本源码阅读之线程池
OkHttp学习(四) 3.10.0版本源码阅读之构建者设计模式
OkHttp学习(五) 3.10.0版本源码阅读之责任链设计模式
OkHttp学习(六) 3.10.0版本源码中的拦截器
OkHttp学习(七) 手写OkHttp之框架搭建
OkHttp学习(八) 手写OkHttp之网络请求实现
OkHttp学习(九) OkHttp的连接池手写实现
OkHttp中使用的责任链模式
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> 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);
}
多个拦截器组成了责任链中每个环节。 成链的关键就是chain.proceed方法中,又new了一自己next,用来调用处理者。 就这么重复调用RealInterceptorChain的proceed方法,形成了链。代码如下:
// 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);
RealInterceptorChain的proceed从构造方法传入的interceptors和index索引找到当前需要的拦截器。new
了一个next对象,interceptors还是同一个,但是index索引加了1,这么一来,这个next这个对象interceptors.get(index);的时候,就是next的拦截器了。
Interceptor
是接口,不同的实现类intercept方法做不一样的事情,但是最终都会调用传进去的next的proceed方法,而这个next就是RealInterceptorChain的对象。然后又new了一个自己,用来调用下一个处理者。
仿照OkHttp的责任链设计模式
责任链各个节点的接口
public interface IBaseTask {
/**
* 参数一:任务节点是否是终止节点的标志位
* 参数二:下一个任务节点
* @param isTask
*/
public void doRunAction(String endFlag, IBaseTask nextTask);
}
链的组装者,将链的每个节点联系到一起
public class ChainManager implements IBaseTask {
private List<IBaseTask> iBaseTaskList = new ArrayList<>();
public void addTask(IBaseTask iBaseTask) {
iBaseTaskList.add(iBaseTask);
}
private int index = 0;
@Override
public void doRunAction(String endFlag, IBaseTask nextTask) {
if (iBaseTaskList.isEmpty()) {
// 抛出异常..
return;
}
if (index == iBaseTaskList.size() || index > iBaseTaskList.size()) {
return;
}
IBaseTask iBaseTaskResult = iBaseTaskList.get(index);
index ++;
iBaseTaskResult.doRunAction(endFlag, nextTask);
}
}
之所以要实现IBaseTask 接口,是为了能直接传递到IBaseTask 接口的方法doRunAction中。
各个任务节点类
拦截器一
public class Task1 implements IBaseTask {
@Override
public void doRunAction(String endFlag, IBaseTask nextTask) { // iBaseTask == ChainManager
System.out.println("拦截器 任务节点一 处理了...");
if ("123".equals(endFlag)) {
return;
}
// 继续执行下一个链条的任务节点 ChainManager.doRunAction("ok", ChainManager)
// ChainManager.doRunAction
nextTask.doRunAction(endFlag, nextTask);
}
}
拦截器二
public class Task2 implements IBaseTask {
@Override
public void doRunAction(String endFlag, IBaseTask nextTask) {
System.out.println("拦截器 任务节点二 处理了...");
if ("end".equals(endFlag)) {
return;
}
// 继续执行下一个链条的任务节点
nextTask.doRunAction(endFlag, nextTask);
}
}
拦截器三
public class Task3 implements IBaseTask {
@Override
public void doRunAction(String endFlag, IBaseTask nextTask) {
System.out.println("拦截器 任务节点三 处理了...");
if ("123".equals(endFlag)) {
return;
}
// 继续执行下一个链条的任务节点
nextTask.doRunAction(endFlag, nextTask);
}
}
测试代码
public class Test {
public static void main(String[] args) {
ChainManager chainManager = new ChainManager();
chainManager.addTask(new Task1());
chainManager.addTask(new Task2());
chainManager.addTask(new Task3());
chainManager.doRunAction("end", chainManager);
}
}
执行结果
拦截器 任务节点一 处理了...
拦截器 任务节点二 处理了...
Process finished with exit code 0
任务一和任务二执行了, 因为任务二的标志位和结束标志位一致,所以任务三并没有执行,而是在任务二的时候就结束了,链也就在这里断了,不再往下执行了。 上面说了ChainManager 也继承IBaseTask是为了能传递下去, 从上面代码不难看出,从始至终只有一个ChainManager对象,贯穿整条链路。因为每次doRunAction的时候,传递的next都是ChainManager这个对象,所以都会执行ChainManager的doRunAction方法,与OkHttp相比,没有每次proceed就new一次ChainManager对象。其它的都是类似的功能了。 只至于OkHttp这么多拦截器都做了什么事情,下回分解。