okhttp源码解析3--拦截器

Okhttpclient流程图.png

拦截器的工作原理

okhttp中拦截器是一个重要的概念,而拦截器中最重要的就是的概念之后,会以这点为核心作出解析。okhttp的日常使用中我们经常都需要对拦截器进行一些重写操作,来满足我们在项目中的需求。常用的interceptornetworkInterceptor,但这里我们暂时不去了解它,在RealCall的execute()中执行了这段代码:

Response response = getResponseWithInterceptorChain();

在请求中通过getResponseWithInterceptorChain拦截器链最终得到返回Response,下面就一步一步的来看看我们是怎么通过拦截器最终获得的这个response

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List 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);
    return chain.proceed(originalRequest);
  }
  • 首先创建集合来添加各种拦截器
  • 创建RealInterceptorChain拦截器链(这里链的概念在拦截器中运用的很深刻)并执行它的proceed方法:
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);
    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");
    }

    return response;
  }

在proceed中代码较多最主要的将它提出来:

    if (index >= interceptors.size()) throw new AssertionError();
  // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, streamAllocation, httpCodec, connection, index + 1, request);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
// Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }
    return response;
  • 创建RealInterceptorChain并且下标为index+1(getResponseWithInterceptorChain()中才创建了一个),index是上一个RealInterceptorChain通过构造器传递下来的
  • 通过下标获取到inercepter调用intercept(next)方法获取到Response并返回。看看 interceptor.intercept(next)接口,实际上就是在此调用它的实现类并通过intercept(Chain chain)得到的Response并返回上一级:
public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;

    Connection connection();
  }
}
  • 这样一级一级的调用什么时候算完了呢?其实在上面的代码中,第一段if (index >= interceptors.size()) throw new AssertionError()就判断了,当下标大于拦截器数量时就抛出异常停止下一级调用了。

就这样拦截器实现了链式调用,使我们一直往下调用拦截器链并通过当前拦截器interceptor.intercept(next)获得response返回给上一个拦截器。这样我们就把所有拦截器都执行完毕,这也是okhttp拦截器的核心逻辑,也是我们如何一步一步获取到接口的返回i

response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);

这里是 RetryAndFollowUpInterceptor的intercept方法中一行代码补充我们上面所得到的结论

总结

  • 先创建拦截器集合
  • 将集合放拦截器链中执行它的processd()方法
  • 在processd()中执行拦截器的通过下标获得此次intercetpor
  • 调用intercepter(Chain chain)方法返回Response并再次执行下一级拦截器链的processd()方法形成链式调用,最终获得一个完整的返回

关于okhttp内部使用的拦截器在okhttp源码解析--五种内部拦截器有所介绍。

你可能感兴趣的:(okhttp源码解析3--拦截器)