okhttp(三)之责任链模式

2020-12-31  本文已影响0人  梦星夜雨

前言

普通的责任链模式我们已经做了分析,这里不再赘述,可以参考责任链模式,这里我们分析下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)进行真正的服务器通信,向服务器发送数据,解析读取的响应数据。

上一篇 下一篇

猜你喜欢

热点阅读