美文网首页
okhttp(三)之责任链模式

okhttp(三)之责任链模式

作者: 梦星夜雨 | 来源:发表于2020-12-31 10:53 被阅读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)进行真正的服务器通信,向服务器发送数据,解析读取的响应数据。

    相关文章

      网友评论

          本文标题:okhttp(三)之责任链模式

          本文链接:https://www.haomeiwen.com/subject/qyrloktx.html