设计模式之:责任链模式应用(Okhttp拦截器)

在 使用OkHttp之前,我们可能用到更多的网络请求框架是 AsyncHttp , 或者直接使用Android 自带的 HttpUrlConnection 和 HttpClient 然后对其简单的封装,Okhttp开源之后,现在大部分项目均支持了 。

private final OkHttpClient client = new OkHttpClient();
 
public void run() throws Exception {
    // 创建Request
    Request request = new Request.Builder()
        .url("http://www.baidu.com/")
        .build();
 
    // 同步获取到结果 (后面我们重点分析下 execute执行逻辑)
    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
    System.out.println(response.body().string());
}
   # RealCall.java

  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    try {
      // 将本次请求添加到事件调度器中
      client.dispatcher().executed(this);
        
      // 今天的主角, 责任链获取到Response结果
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
  }

上面Client执行调度器中的 excute方法,实际上就是将当前请求直接添加到这个同步的双端队列中,等待线程池中的队列被执行。

---------------getResponseWithInterceptorChain() 这个就是今天的主角拦截器,而拦截器就是使用了 责任链模式,我们看看OkHttp 是怎样通过责任链模式,一环接着一环 ,一个对象持有下一个对象的引用。

1: 构建5个拦截器放在 拦截器数组里面,然后作为参数新建一个RealInterceptorChain.java,作为第一个拦截器。(index= 0)

2: 通过当前 Chain.proceed(request) 获取当前的拦截器(就是你自定义的拦截器),并得到下一个 RealInterceptorChain (index + 1),传入 当前的拦截器

3:在当前的拦截器中因为 同步步骤2 保存了 下一个 Chain ,所以可以根据下一个 Chain.proceed() 来循环到下一个拦截器,同时你也可以在当前的拦截器中 对 Response追加自己的业务,然后返回Response

 # RealCall.java

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.

    //责任链 实际上是像递归一样倒叙执行
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    //5、重试与重定向拦击器
    interceptors.add(retryAndFollowUpInterceptor);
    // 4、请求头等信息 拦截器
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //3、缓存配置 根据条件(存在响应缓存并被设置为不变的或者响应在有效期内)返回缓存响应设置请求头(If-None-Match、If-Modified-Since等) 服务器可能返回304(未修改)
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //2、连接 拦截器
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }

    //1、流操作(写出请求体、获得响应数据)进行http请求报文的封装与请求报文的解析
    interceptors.add(new CallServerInterceptor(forWebSocket));

    // 新建一个 RealInterceptirChain.class 类,执行 责任链中抽象处理类的处理方法 proceed
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null,
          0, originalRequest);

    return chain.proceed(originalRequest);
  }
# RealInterceptorChain.proceed


    //拦截器列表,装载了所有拦截器
  private final List<Interceptor> interceptors;
  
  //拦截器列表索引 (从零开始,每次 新建一个RealInterceptorChain对象,index在新建时候就增加1)
  private final int index;


  //封装请求信息的对象
  private final Request request;

  //proceed方法执行次数
  private int calls;


  //  构造函数
  public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation 
            streamAllocation,
      HttpCodec httpCodec, RealConnection connection, int index, Request request) {
    this.interceptors = interceptors;
    this.connection = connection;
    this.streamAllocation = streamAllocation;
    this.httpCodec = httpCodec;
    this.index = index;
    this.request = request;
  }



========================================================================================


  @Override 
  public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }
 
  /**
  * 依次取出拦截器链表中的每个拦截器去获取Response
  */
  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    //如果索引值大于等于拦截器列表大小,就抛出异常,因为后续会出现数组越界的异常
    if (index >= interceptors.size()) throw new AssertionError();
    

    // 创建新的拦截器链对象,并将index索引+1
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, streamAllocation, httpCodec, connection, index + 1, request);
    //获取当前拦截器
    Interceptor interceptor = interceptors.get(index);
    
    //执行拦截器的intercept方法获取结果,并将新的拦截器链对象传入(这就是当前对象保留下一个对象的引 
     用)
    Response response = interceptor.intercept(next);

   
    return response;
  }

好重点来了,当我们自己需要给某个 拦截器 在Response追加一些返回内容时,那么我们可以自定义 Interceptor 重写 intercept函数即可

public class LogInterceptor implements Interceptor {

    private static final String TAG = "LogInterceptor";

    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {
        Request request = chain.request();

        long t1 = System.nanoTime();
        Log.d(TAG, "request = " + request.toString());
        
        Response response = chain.proceed(request);

        long t2 = System.nanoTime();
        //1e6d = 10的6的方
        Log.d(TAG, "time cost = " + (t2 - t1) / 1e6d + "ms \n response = " + response.toString());
        
        //  chain.proceed(request) 将业务交给下一个责任认处理
        return response;
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值