OkHttp 源码分析(一)拦截器执行流程

目录

拦截器启动流程代码分析

拦截器怎么串行起来呢?

拦截器如何停下来


  • 拦截器启动流程代码分析

拦截器的创建初始化以及启动过程,主要有3个步骤

  • 创建拦截器集合;
  • 创建串行职责链并放入拦截器集合以及初始索引;
  • 启动串行拦截器;

具体的执行流程如下图

拦截器的主要逻辑在 RealCall.getResponseWithInterceptorChain()中

Response getResponseWithInterceptorChain() throws IOException {
    // 1.创建拦截器集合
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    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));

    // 2.创建串行职责链并放入拦截器集合以及初始索引
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    boolean calledNoMoreExchanges = false;
    try {
      // 3. 启动串行拦截器
      Response response = chain.proceed(originalRequest);
      if (transmitter.isCanceled()) {
        closeQuietly(response);
        throw new IOException("Canceled");
      }
      return response;
    } catch (IOException e) {
      calledNoMoreExchanges = true;
      throw transmitter.noMoreExchanges(e);
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null);
      }
    }
  }

在上面的代码段中,我们可以看到拦截器的创建初始化以及启动过程,主要有3个步骤

  • 创建拦截器集合;

在创建拦截器中会看到有几个比较重要的点,应用拦截器、默认拦截器、网络拦截器都会在这里装载;

装载应用拦截器

interceptors.addAll(client.interceptors());

装载默认拦截器

interceptors.add(new RetryAndFollowUpInterceptor(client));
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));
  • 创建串行职责链并放入拦截器集合以及初始索引;

在这里创建了一个串行职责链对象 RealInterceptorChain,并在构建中传入了拦截器集合 interceptors 和 index 为0的下标。

Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
     originalRequest, this, client.connectTimeoutMillis(),
     client.readTimeoutMillis(), client.writeTimeoutMillis());
  • 启动串行拦截器;

Response response = chain.proceed(originalRequest);

在这里我们看到chain已经开始执行了,我们在具体看下proceed方法

// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);

在这里可以看到真正的启动,通过index 获得Interceptor实例,并调用intercept方法,执行拦截逻辑。

  • 拦截器怎么串行起来呢?

上文中,我们已经分析到拦截器的运行,调用Interceptor实例的intercept方法,那么关于拦截器如何串行起来,我们需要看一下intercept方法的实现。以 BridgeInterceptor 为例

public Response intercept(Chain chain) throws IOException {
    // 业务逻辑 ..... 
    Response networkResponse = chain.proceed(requestBuilder.build());
    // .......
}

我们可以看到在intercept方法中又调用 chain的proceed方法,这里的调用又回到了上文的步骤3,而每个拦截器都会在完成业务逻辑后执行proceed,这样拦截器就串行起来了。这点官方的文档中也有提到

A call to chain.proceed(request) is a critical part of each interceptor’s implementation. 

  • 拦截器如何停下来

上文已经分析了拦截器如何开始,那么如何停下来的问题,关键还是在于proceed方法,最后一个拦截器不再调用proceed方法,那么拦截器也就停下来了。

那么如何保证最后一个拦截器不调用proceed,这点在 RealCall的 getResponseWithInterceptorChain方法中可以保证,因为拦截器是有序的,并且最后一个添加的是CallServerInterceptor,而这个拦截器并没有调用,所以 CallServerInterceptor可以保证拦截器一定可以停下来。

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    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));
    // ....
  }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值