OkHttp3源码解析--拦截器链

前面说到的同步请求RealCall和异步请求AsyncCall,在执行execute方法时都会执行下面一句:


Response response = getResponseWithInterceptorChain();

这一句就是调用了拦截器链,执行了一系列操作,完成了请求访问,并将结果返回。

RealCall#getResponseWithInterceptorChain

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());//添加 OkHttpClient 时设置的 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());
    //执行拦截器链的proceed方法,依次执行上面所有的拦截器的功能
    return chain.proceed(originalRequest);
  }

上述代码说明:

  • 创建了一个Interceptor列表;

  • 依次添加拦截器,添加的顺序为:client.interceptors()–>retryAndFollowUpInterceptor–>BridgeInterceptor–>CacheInterceptor–>ConnectInterceptor–>networkInterceptors–>CallServerInterceptor;

  • 创建Interceptor.Chain对象,参数有:

    • 拦截器集合interceptors;

    • originalRequest;

    • RealCall;

    • eventListener;

    • 连接超时时间,读超时时间,写超时时间。

RealInterceptorChain的创建

Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());public interface Interceptor {
  //负责拦截
  Response intercept(Chain chain) throws IOException;
  interface Chain {
    //可以返回Request对象
    Request request();
    //前进,推动继续进行,负责不断执行下一个拦截器
    Response proceed(Request request) throws IOException;
    /**
     * Returns the connection the request will be executed on. This is only available in the chains
     * of network interceptors; for application interceptors this is always null.
     */
    //返回当前请求所在的连接对象。
    @Nullable Connection connection();
    //返回Call对象
    Call call();
  }
}public final class RealInterceptorChain implements Interceptor.Chain {
  private final List<Interceptor> interceptors;//拦截器集合,即拦截器链中的拦截器
  private final StreamAllocation streamAllocation;//流分配器
  private final HttpCodec httpCodec;//Http 流
  private final RealConnection connection;//真正的连接对象
  private final int index;//final类型的,是访问拦截器集合的index
  private final Request request;//请求Request
  private final Call call;//传过来的RealCall
  private final EventListener eventListener;
  private final int connectTimeout;//连接超时时间
  private final int readTimeout;//读超时时间
  private final int writeTimeout;//写超时时间
  private int calls;//表示访问拦截器链的次数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;
    this.connection = connection;//null
    this.streamAllocation = streamAllocation;//null
    this.httpCodec = httpCodec;//null
    this.index = index;//0
    this.request = request;
    this.call = call;
    this.eventListener = eventListener;
    this.connectTimeout = connectTimeout;
    this.readTimeout = readTimeout;
    this.writeTimeout = writeTimeout;
  }
}

通过以上代码,创建完成了RealInterceptorChain对象。接下来就是调用proceed方法。

RealInterceptorChain#proceed

@Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }
  //目前入参情况:
  //request != null
  //streamAllocation == null
  //httpCodec == null
  //connection == null
  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    //判断当前的访问索引是否超过了拦截器集合中拦截器的数量,index是不断增加的。
    if (index >= interceptors.size()) throw new AssertionError();
​
    calls++;// If we already have a stream, confirm that the incoming request will use it.
    //如果当前已经有一个流,确认当前这个Request是否可以用它这个链接
    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对象。这里的传入的拦截器集合访问的索引是index+1,call也是增加了1.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);//获取当前index对应的Interceptor;
    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;//返回响应
  }

上面,第一次创建RealInterceptorChain对象,并调用proceed方法 的过程:

  • 判断当前的访问索引是否超过了拦截器集合中拦截器的数量;

  • 创建下一个RealInterceptorChain对象。这里的传入的拦截器集合访问的索引是index+1;

  • 获取当前index对应的interceptor;

  • 调用当前interceptor的intercept方法,处理当前拦截器负责的业务,并唤起下一个拦截器;

  • 当前request != null

     streamAllocation == null
    
     httpCodec == null
    
     connection == null
    

拦截器集合中的第一个拦截器为retryAndFollowUpInterceptor,首先将进入到它的intercept方法:

RetryAndFollowUpInterceptor#intercept

public final class RetryAndFollowUpInterceptor implements Interceptor {
  /**
   * How many redirects and auth challenges should we attempt? Chrome follows 21 redirects; Firefox,
   * curl, and wget follow 20; Safari follows 16; and HTTP/1.0 recommends 5.
   */
  private static final int MAX_FOLLOW_UPS = 20;
  private final OkHttpClient client;//前面创建的OkHttpClient对象
  private final boolean forWebSocket;
  private StreamAllocation streamAllocation;
  private Object callStackTrace;
  private volatile boolean canceled;//请求是否被取消//Chain为 RealInterceptorChain对象,在上一个拦截器中创建并传入到这里
@Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();//获取Request对象
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Call call = realChain.call();//获取RealCall对象
    EventListener eventListener = realChain.eventListener();
    //创建StreamAllocation对象,之前都是null。
    streamAllocation = new StreamAllocation(client.connectionPool(), createAddress(request.url()),
        call, eventListener, callStackTrace);int followUpCount = 0;//从定向次数
    Response priorResponse = null;
    while (true) {//一直循环
      if (canceled) {//判断是否取消了请求
        streamAllocation.release();//释放资源
        throw new IOException("Canceled");
      }
​
      Response response;
      boolean releaseConnection = true;
      try {
        //继续执行下一个拦截器,看上面的proceed方法
        response = realChain.proceed(request, streamAllocation, null, null);
        releaseConnection = false;
      } catch (RouteException e) {
        // The attempt to connect via a route failed. The request will not have been sent.
        if (!recover(e.getLastConnectException(), false, request)) {
          throw e.getLastConnectException();
        }
        releaseConnection = false;
        continue;
      } catch (IOException e) {
        // An attempt to communicate with a server failed. The request may have been sent.
        boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
        if (!recover(e, requestSendStarted, request)) throw e;
        releaseConnection = false;
        continue;
      } finally {
        // We're throwing an unchecked exception. Release any resources.
        if (releaseConnection) {
          streamAllocation.streamFailed(null);
          streamAllocation.release();
        }
      }
  }
}

和上述过程类似,将继续执行下一个拦截器的intercept方法.

上面就了解了拦截器链是怎么依次执行每一个拦截器的。

总结一下拦截器链中拦截器的调用过程中:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值