OkHttp3.0(四)-Interceptor拦截器(1)-拦截器链Chain

1.引言

我们在前面几个章节的学习过程中,已经可以明白OkHttp的基本使用OkHttp在使用的过程中几个常用的类的分析OkHttp的分配器Dispatcher。其中在RealCall中,不管是同步请求还是异步请求,最终都会调用的一个方法,得到网络请求响应结果Response,就是getResponseWithInterceptorChain()方法。因为这个方法用的是拦截器链调用拦截器执行对应的方法,所以我们决定放到现在来讲,我们先看一下getResponseWithInterceptorChain()的调用位置:

 //同步请求获取请求结果
 @Override public Response execute() throws IOException {
    ...
    try {
      ...
      Response result = getResponseWithInterceptorChain();//获取请求结果
      ...
      return result;
    } catch (IOException e) {
      ...
    } finally {
      ...
    }
  }

上面我们看到的,是我们调用Call的同步请求方法execute()时,的部分代码,可以看到,在该方法中真正获取请求结果的只有一句代码Response result = getResponseWithInterceptorChain(),就是说,同步请求会直接调用getResponseWithInterceptorChain()方法,获取Response并返回个调用者。

我们再看异步请求是如何调用的getResponseWithInterceptorChain()方法,首先我们异步请求调用的是Call的enqueue(Callback)方法:

 //Call的异步请求方法,请求结果会利用Callback接口回调返回给调用者
 @Override public void enqueue(Callback responseCallback) {
    ...
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

通过部分代码,我们看到,Call的enqueue(Callback)方法,会调用Dispatcher的enqueue(AsyncCall)方法,我们继续看一下Dispatcher的enqueue(AsyncCall)方法:

 //Dispatcher的异步请求方法,被Call调用。Asyncall是异步请求任务
 synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);//线程池执行异步任务,最终会执行AsyncCall的execute()方法
    } else {
      readyAsyncCalls.add(call);
    }
  }

上面的代码我们前面已经讲过多次,executorService().execute(call)使用线程池异步执行了异步请求任务,其中的请求任务代码,在AsyncCall类的execute()方法中,相当于在异步线程中执行了AsyncCall类的execute()方法,所以我们在跳转到AsyncCall类中,查看一下它的execute()方法:

 //RealCall的内部类AsyncCall,用来做异步请求任务,是Runnable的子类。  
 @Override protected void execute() {
      ...
      try {
        //获取请求结果
        Response response = getResponseWithInterceptorChain();
        if (...) {
          ...//判断,使用Callback接口回调返回给调用者
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
         ...//判断,使用Callback接口回调返回给调用者
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
         ...
        } else {
          ...//判断,使用Callback接口回调返回给调用者
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        ...
      }
    }

上面代码,相信大家都能看懂,在AsyncCall的execute()方法中调用了getResponseWithInterceptorChain()方法。获取到了请求结果,然后经过判断,在利用调用者传进来的Callback接口,做接口回调,将结果回传给调用者,完成了异步请求。

2.getResponseWithInterceptorChain()方法

前面说了这么多,就是为了说明不管是同步请求还是异步请求,都会调用RealCall中的getResponseWithInterceptorChain()来获取请求结果Response,所以我们现在将getResponseWithInterceptorChain()代码放上来,分析一下:

//RealCall的同步、异步请求都会调用此方法,这是获取网络请求结果Response的关键方法 
Response getResponseWithInterceptorChain() throws IOException {
    //创建一个存储拦截器的集合
    List<Interceptor> interceptors = new ArrayList<>();
    //将用户传入的Application拦截器添加到集合中
    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) {//如果不是WebSocket连接
      //将用户传入的Network拦截器加入的
      interceptors.addAll(client.networkInterceptors());
    }
    //将CallServer拦截器(与服务器进行数据交互)加入到集合中
    interceptors.add(new CallServerInterceptor(forWebSocket));
    //创建拦截器链,index初始值为0
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
    //调用拦截器链的proceed方法,就会调用到所有拦截器,并返回请求结果Response
    return chain.proceed(originalRequest);
  }

这一节,我们先不讲代码中提到的每个拦截器的作用,我们只讲拦截器的调用。我们从上面代码中可以看到,首先会将各种拦截器按照先后顺序,分别加入到新创建的ArryList集合中,然后创建了Interceptor.Chain拦截器链实例,在创建过程中,构造函数传入了存有各种拦截器的集合interceptors、数字0、用户创建好的Request对象、当前RealCall对象、OkHttp网络请求详细事件回调接口、超时设置。最后,调用了拦截器链chain的proceed(Request)方法,该方法返回Response正是调用者需要的服务器端的响应结果。我们先大概知道一下,这个方法中,主要做了些什么工作。接下来我们来看拦截器链。

3.Interceptor.Chain,拦截器链

首先我们通过代码查找,看到Interceptor.Chain是一个interface,它的目前唯一实现类就是RealInterceptorChain,我们看下这个类的构造方法

//RealInterceptorChain构造方法
public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
      HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
      EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
    this.interceptors = interceptors;//RealCall那边创建好并且已经添加好了所有拦截器
    this.connection = connection;//null
    this.streamAllocation = streamAllocation;//null
    this.httpCodec = httpCodec;//null
    this.index = index;//RealCall传入的是0
    this.request = request;//用户构建好的Request
    this.call = call;//当前RealCall
    this.eventListener = eventListener;
    this.connectTimeout = connectTimeout;
    this.readTimeout = readTimeout;
    this.writeTimeout = writeTimeout;
  }

我们需要注意一点,他的变量index正是我们刚才RealCall的getResponseWithInterceptorChain()方法中传入的0,我们接着看一下我们前面调用的RealInterceptorChain的proceed(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 {
    ...
    //这里需要注意,创建的拦截器链RealInterceptorChain,传入的参数中(index+1)
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    //这里需要注意,获取到的拦截器是角标为index的拦截器,而index正是通过其构造函数赋值的
    Interceptor interceptor = interceptors.get(index);
    //调用拦截器的intercept()方法获取Response
    Response response = interceptor.intercept(next);
    ...
    return response;//将请求结果返回
  }

讲到这里,可能很多人还是有些懵懵懂懂,我来帮大家捋一下:

1、在RealCall的getResponseWithInterceptorChain()方法中,我们第一次创建了拦截器链对象RealInterceptorChain,将存有拦截器的集合interceptors传给了RealInterceptorChain,同时设置了它的index为0,紧接着调用了RealInterceptorChain的proceed方法;

2、在RealInterceptorChain的proceed方法中,再次创建了RealInterceptorChain的实例,继续将存有拦截器的集合interceptors传递给新创建的RealInterceptorChain,这时给他设置的index为当前index+1,然后从interceptors中获取角标为当前index的Interceptor,执行Interceptor的intercept(Chain)方法,参数Chain就是新创建的index+1的RealInterceptorChain对象,并将获取到的Response返回给上一个调用者;

3、Interceptor本身是interface,其intercept(Chain)方法具体看它的实现类,可以肯定的一点是,intercept(Chain)方法中,除了做拦截器本身该做的一些操作外,会继续调用Chain的proceed方法,进入Chain的proceed方法中继续创建index+1的Chain,并且获取角标为index的Interceptor,调用它的intercept(Chain)方法......一直调用下去,直到最后一个拦截器为止。

上面我说捋一下,我想还有人不太明白,因为到现在为止,还缺少一部分代码,那就是Interceptor的intercept(Chain)方法究竟是怎么样子的,我们先看下Interceptor接口的类继承情况

其中LoggingInterceptor是我自己创建的继承自Interceptor,其他五个都是OkHttp框架已经提供的拦截器,我们在刚才讲getResponseWithInterceptorChain()方法时候,都见过的,先不纠结每一个拦截器的作用。我们主要是为了研究一下这些拦截器的intercept(Chain)方法。getResponseWithInterceptorChain()方法创建了存储拦截器的ArrayList集合,并且将拦截器都存入了该集合,我们刚才提到,会根据顺序,每次index+1来获取interceptors中的Interceptor,并调用其intercept(Chain)方法。我们取两个具有代表性的进行研究,这五个拦截器中,按照添加顺序排在最前面的RetryAndFollowUpInterceptor和排在最后的CallServerInterceptor,分别看一下他们的intercept(Chain)方法

RetryAndFollowUpInterceptor的intercept(Chain)方法

 @Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    ...
    StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
        createAddress(request.url()), call, eventListener, callStackTrace);
    ...
    while (true) {
     ...//此处调用了拦截器链RealInterceptorChain的proceed方法
        response = realChain.proceed(request, streamAllocation, null, null);
     ...
        return response;
       ...
    }
  }

我们可以发现,在RetryAndFollowUpInterceptor的intercept(Chain)方法中,的确调用了拦截器链RealInterceptorChain的proceed()方法,这样就可以继续往下,调用下一个Interceptor的intercept(Chain)方法,一直调用下去,直到最后一个拦截器CallServerInterceptor结束。

CallServerInterceptor的intercept(Chain)

//这是CallServerInterceptor的intercept(Chain)方法,该方法不会调用Chain的proceed方法 
@Override public Response intercept(Chain chain) throws IOException {
    ...
    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();
    ...
    return response;
  }

通过仔细阅读该代码,发现CallServerInterceptor果然没有继续调用Chain的proceed方法。拦截器链Chain的proceed方法,第一次调用,是被RealCall类的getResponseWithInterceptorChain()方法,然后proceed获取角标为index的Interceptor,调用Interceptor的intercept(Chain)方法,index+1,intercept(Chain)方法继续调用下一个RealInterceptorChain的proceed方法,一直这样调用下去,直到最后一个拦截器,这就是拦截器链的调用。

4.总结

我们先通过两幅幅图来描述拦截器链的工作

我们来简单的总结一下本章要跟大家分享的:

1、OkHttp的网络请求,其本质上是由拦截器链的调用完成的;

2、拦截器链的调用,起始于RealCall的getResponseWithInterceptorChain方法,结束与最后一个拦截器CallServerInterceptor的intercept(Chain)方法;

3、连接器链的调用,RealInterceptorChain的作用是按照顺序依次调用每一个拦截器的intercept(Chain)方法。拦截器Interceptor的作用是发挥自身拦截器的特性,对Request和Response做出操作,调用RealInterceptorChain的proceed()方法,让其继续下去;

4、我们可以将拦截器的调用看作递归,逐层向下调用,直到最后一个拦截器返回Response,然后在逐层向上,一边处理Response一边返回给上一层,最终返回给调用。

本章节关于拦截器链的讲解到此结束了,拦截器是OkHttp框架的精髓,所以我们会拿出几篇文章来详细分析,下一章节开始我们将分析每一个拦截器。

 

 

 

 

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值