OkHttp 源码学习(二)基本流程

本节将对okhttp中的关键的类和方法进行简单介绍,并梳理出执行的基本流程进行,让大家对源码有一个全局的认识。

Class Call

回顾我们上节中出现的Call对象,这个Call是什么呢?

Call对象其实就是一个准备好执行网络请求的request,是对request进行了封装,支持取消。由于一个Call对象表示的是请求和响应流,因此同一个Call不能执行两次。

Class Dispatcher

在讲Dispatcher之前我们还是来回顾一下如何我们在执行同步或异步请求,分别是执行了Call的execute()和enqueue()方法。下面我们就来看一下这两个方法的源码。

首先,我们来看一下execute():

@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 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.dispatcher()返回就是Dispatcher对象,跟踪源码我们发现这个Dispatcher其实是client的成员变量。接下来我们再看看enqueue():

@Override public void enqueue(Callback responseCallback) {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  eventListener.callStart(this);
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

这里同样使用了client.dispatcher(),看到这里大家就知道了,同步和异步请求其实都是通过这个Dispatcher来完成的。那么我们就来了解一下Dispatcher是什么?

Dispatcher负责okhttp的任务调度,管理同步/异步的请求状态,并维护一个线程池,用于执行请求,是Okhttp的核心类。

Method getResponseWithInterceptorChain()

接下来我将带大家了解一下这个关键的方法,顾名思义,这个方法是用于获取请求的Response的。
回到上面同步请求execute()方法中,我们可以发现该方法内部就是通过调用这个getResponseWithInterceptorChain()来获取请求的Response。其实异步请求enqueue()方法最终也是通过调用这个方法来获取请求的Response的。这里我带大家了解一下enqueue()方法如何调用这个方法的。
回到enqueue()方法中,我们可以发现异步请求是通过client.dispatcher().enqueue(new AsyncCall(responseCallback))来实现的。我们先看一下enqueue()方法中参数new AsyncCall(responseCallback)的源码。

 final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

    String host() {
      return originalRequest.url().host();
    }

    Request request() {
      return originalRequest;
    }

    RealCall get() {
      return RealCall.this;
    }

    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

我们发现这个AsyncCall内部类其实是一个Runnable。我们再来看一下Dispatcher的enqueue()方法的源码。

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

我们发现executorService().execute(call)其实就是通过Dispatcher中的线程池来执行这个AsyncCall Runnable的。这样我们再回过头来看看这个AsyncCallexecute ()方法,其实就是在这里调用了getResponseWithInterceptorChain()来获取请求的Response。
讲到这里,大家是不是开始对这个getResponseWithInterceptorChain()方法十分好奇了,这个方法是如何获取请求的Response。当然我们还是一起来看一下源码。

  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());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }

这段代码大家看起来可能会很奇怪,这里怎么出现这么多interceptor,大伙也没看到请求,为啥这里就直接返回了response了。其实,这里采用了责任链模式,来实现最终的请求response。具体如何实现的我会在后面的文章中给大家一一说明,这里就不展开了说。

Interceptor

Interceptor也是okhttp的核心之一,它把实际的网络重试、重定向、缓存、透明压缩、网络连接等功能拆分到独立的interceptor中,再通过Interceptor.Chain将这些功能环环相扣起来,最终完美实现网络请求。
我将在接下来的文章中讲述以上方法中的5个重要的拦截器interceptor:

  • RetryAndFollowUpInterceptor: 主要用于重试和重定向请求
  • CacheInterceptor: 处理缓存拦截器
  • BridgeInterceptor: 负责okhttp请求和响应对象与实际http协议中请求和响应对象之间的转换。同时处理cookies相关内容
  • ConnectionInterceptor: 负责建立连接和流对象
  • CallServerInterceptor: 负责完成最终的网络请求,发送请求和读取响应

基本流程图

本节最后放一张流程图,将以上几个重要的概念串联起来,便于大家从全局来认识一下okhttp。

《OkHttp 源码学习(二)基本流程》 okhttp基本流程图

在接下来的章节中,我将结合以上的基本流程图带着大家深入分析源码。
【附录】

《OkHttp 源码学习(二)基本流程》 资料图

需要资料的朋友可以加入Android架构交流QQ群聊:513088520

点击链接加入群聊【Android移动架构总群】:加入群聊

获取免费学习视频,学习大纲另外还有像高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)等Android高阶开发资料免费分享。

    原文作者:Android架构
    原文地址: https://www.jianshu.com/p/dca3eb6d5ecc
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞