前言
普通的责任链模式我们已经做了分析,这里不再赘述,可以参考责任链模式,这里我们分析下okhttp的责任链模式。
我们先用简化版的责任链模式进行分析:
public interface IBaseLogger {
public static int INFO = 1;
public static int DEBUG = 2;
public static int ERROR = 3;
void logMessage(int level,IBaseLogger iBaseLogger,String message);
}
这里我们定义一个IBaseLogger 接口。下面是依旧是三个扩展实体类。
public class ErrorLogger implements IBaseLogger{
@Override
public void logMessage(int level, IBaseLogger iBaseLogger, String message) {
// TODO Auto-generated method stub
if(IBaseLogger.ERROR == level){
System.out.println("Error::Logger: " + message);
} else {
iBaseLogger.logMessage(level, iBaseLogger, message);
}
}
}
public class DebugLogger implements IBaseLogger{
@Override
public void logMessage(int level, IBaseLogger iBaseLogger, String message) {
// TODO Auto-generated method stub
if(IBaseLogger.DEBUG == level){
System.out.println("Debug::Logger: " + message);
} else {
iBaseLogger.logMessage(level, iBaseLogger, message);
}
}
}
public class InfoLogger implements IBaseLogger{
@Override
public void logMessage(int level, IBaseLogger iBaseLogger, String message) {
// TODO Auto-generated method stub
if(IBaseLogger.INFO == level){
System.out.println("Info::Logger: " + message);
} else {
iBaseLogger.logMessage(level, iBaseLogger, message);
}
}
}
扩展实体类判断当前任务是否要在本链条中执行。
public class LoggerManager implements IBaseLogger{
private ArrayList<IBaseLogger> iBaseLoggerList = new ArrayList<IBaseLogger>();
public void addLogger(IBaseLogger iBaseLogger){
iBaseLoggerList.add(iBaseLogger);
}
private int index;
@Override
public void logMessage(int level, IBaseLogger iBaseLogger, String message) {
// TODO Auto-generated method stub
if (iBaseLoggerList.isEmpty()) {
// 抛出异常..
throw new NullPointerException("iBaseLoggerList is empty");
}
if (index >= iBaseLoggerList.size()) {
throw new IndexOutOfBoundsException();
}
IBaseLogger iBaseLoggerResult = iBaseLoggerList.get(index);
index++;
iBaseLoggerResult.logMessage(level, iBaseLogger, message);
}
//简单复位操作,防止多次调用后不是从链条头开始执行
public void reset() {
index = 0;
}
}
这是一个链条的管理类,定义了一个IBaseLogger的链表,
定义了一个将日志管理器加入链表的方法,
定义了一个index的标识来判断当前执行到了哪个链条。
最后在logMessage根据当前联调所处的位置取出相应的日志管理器,执行具体功能。
下面是具体的调用和测试数据。
public class ChainTest {
public static void main(String[] args){
LoggerManager loggerManager = new LoggerManager();
loggerManager.addLogger(new ErrorLogger());
loggerManager.addLogger(new DebugLogger());
loggerManager.addLogger(new InfoLogger());
loggerManager.logMessage(AbstractLogger.INFO, loggerManager,
"This is an info information.");
loggerManager.reset();
loggerManager.logMessage(AbstractLogger.DEBUG, loggerManager,
"This is a debug information.");
loggerManager.reset();
loggerManager.logMessage(AbstractLogger.ERROR, loggerManager,
"This is an error information.");
}
}
Info::Logger: This is an info information.
Debug::Logger: This is a debug information.
Error::Logger: This is an error information.
下面我们分析一下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);
}
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 < 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");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;
}
看源代码可以知道okhttp也采用了一个拦截器的集合将所需要的拦截器,也是才用了在拦截器管理器的方式进行了数据请求,如果某个拦截器抛出了异常或者得到了结果,就将流程终止。和上述简单化版的流程是一样的。
这里我们再介绍下各个拦截器的功能:
1.重试与重定向拦截器(RetryAndFollowUpInterceptor)负责判断用户是否取消了请求,在获得了结果之后,会根据响应码判断是否需要重新定向,如果满足条件就会重启执行所有拦截器。
2.桥接拦截器(BridgeInterceptor)负责将HTTP协议必备的请求头加入其中(如:Host)并加入一些默认行为(如:GZIP压缩),在获得结果后,调用保存coockie接口并解析GZIP数据。
3.缓存拦截器(CacheInterceptor)负责交出之前读取数据并判断是否缓存,获取结果后判断是否缓存。
4.连接拦截器(ConnectInterceptor)负责找到或者邪见一个链接,并获得对应的socket流,在获得结果后不进行额外的处理。
5.请求服务器拦截器(CallServerInterceptor)进行真正的服务器通信,向服务器发送数据,解析读取的响应数据。
网友评论