OKHttp3部分源码阅读

当我们想要将OKHttp3集成进我们的项目中时,我们便会需要使用 OkHttpClient.Builder()方法去创建一个OkHttpClient实例,而在OkHttpClient中就包含了如下属性:

  final Dispatcher dispatcher;
  final Proxy proxy;
  final List<Protocol> protocols;
  final List<ConnectionSpec> connectionSpecs;
  final List<Interceptor> interceptors;
  final List<Interceptor> networkInterceptors;
  final ProxySelector proxySelector;
  final CookieJar cookieJar;
  final Cache cache;
  final InternalCache internalCache;
  final SocketFactory socketFactory;
  final SSLSocketFactory sslSocketFactory;
  final CertificateChainCleaner certificateChainCleaner;
  final HostnameVerifier hostnameVerifier;
  final CertificatePinner certificatePinner;
  final Authenticator proxyAuthenticator;
  final Authenticator authenticator;
  final ConnectionPool connectionPool;
  final Dns dns;
  final boolean followSslRedirects;
  final boolean followRedirects;
  final boolean retryOnConnectionFailure;
  final int connectTimeout;
  final int readTimeout;
  final int writeTimeout;
  final int pingInterval;

属性非常的多,与本次分析源码很相关的有:Dispatcher-用来进行请求的分发,Interceptor-拦截器。

有趣的是,在构建OkHttpClient时,引入了Builder模式,即在设置OkHttpClient某项属性的值时,返回OkHttpClient自身,这样便可以采用链式编码的形式去进行OkHttpClient的各项属性的依次设置。

接下来分析网络请求的每一步。

一,当我们想要去执行网路请求时,一般如下调用:

reponse = okHttpClient.newCall(request).execute();

可以看到这里首先调用了okHttpClient中的newCall()方法,获得了一个RealCall的实例,那么我们看一下RealCall到底是什么。

final class RealCall implements Call {
  final OkHttpClient client;
  final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;

  /** The application's original request unadulterated by redirects or auth headers. */
  final Request originalRequest;
  final boolean forWebSocket;

  // Guarded by this.
  private boolean executed;

  RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

  @Override 
  public Request request() {
    ...
  }

  @Override 
  public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }

  private void captureCallStackTrace() {
    ...
  }

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

  @Override 
  public void cancel() {
    ...
  }

  @Override 
  public synchronized boolean isExecuted() {
    ...
  }

  @Override 
  public boolean isCanceled() {
    ...
  }

 
  final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

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

    String host() {
      ...
    }

    Request request() {
      ...
    }

    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 {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

  /**
   * Returns a string that describes this call. Doesn't include a full URL as that might contain
   * sensitive information.
   */
  String toLoggableString() {
    ...
  }

  String redactedUrl() {
    ...
  }

  Response getResponseWithInterceptorChain() throws IOException {
    ...
  }
}

上面的代码太多,其实目前只需要关注一个方法–execute(),因为这个方法是在我们进行网络请求时调用的方法,如下:

reponse = okHttpClient.newCall(request).execute();

接下来分析 execute() 方法的步骤:

  @Override
  public Response execute() throws IOException {
    
    //进行判断,不让请求被重复执行。因为每一个request都被封装成了RealCall,而RealCall中又有着一个字段--executed 来保存当前请求是否被执行。
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }

如上面代码中描述的,当当前的请求RealCall没有被执行过时,便会开始请求的执行。首先会调用分发器Dispatcher中的executed(this)方法,且将当前RealCall作为了传入参数。那么 Dispatcher 到底是一个怎么样子的分发器呢。我们看看Dispatcher 的代码:

public final class Dispatcher {
  private int maxRequests = 64;
  private int maxRequestsPerHost = 5;
  private Runnable idleCallback;

  /** Executes calls. Created lazily. */
  private ExecutorService executorService;

  /** Ready async calls in the order they'll be run. */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

可以看到Dispatcher中有几个比较重要的成员变量

  1. maxRequests – 最大请求数
  2. maxRequestsPerHost - 每个host的最大请求数
  3. executorService - 一个线程池
  4. readyAsyncCalls - 异步就绪等待队列
  5. runningAsyncCalls - 异步执行队列
  6. runningSyncCalls - 同步执行队列。

我们在执行请求时,是首先进行了如下调用:

client.dispatcher().executed(this);

这一行代码是在干嘛呢?

 /** Used by {@code Call#execute} to signal it is in-flight. */
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

哦,原来是在将当前的请求 RealCall添加进异步执行队列中。
接下来使用了拦截器进行了一系列拦截操作,我们可以看到,在这段try代码中,后面还有一个 finally{} 代码段

finally {
      client.dispatcher().finished(this);
}

这段代码在干嘛呢?到现在我们还没有看到真正的执行网路请求的部分,那么网络请求的执行会不会就是在finished()方法中呢?
可以看到finished(realcall)方法实际是调用的finished(runningSyncCalls, realcall, false)方法。

 /** Used by {@code Call#execute} to signal completion. */
  void finished(RealCall call) {
    finished(runningSyncCalls, call, false);
  }

那么finished(runningSyncCalls, realcall, false)方法里面又在干嘛呢,这个方法的参数有三个

  1. 任务队列 - runningSyncCalls
  2. 请求任务 - realCall
  3. promoteCall - 这个是什么呢?不造

我们把finished(runningSyncCalls, realcall, false)方法的代码贴出来:

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    //一个runnable对象,真正的任务执行体
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }

从上面可以知道,我们该finished()方法的第三个参数是 false,因此一定会执行到if (promoteCalls) promoteCalls();这一步。那么在promoteCalls() 方法里面干了什么呢?

private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();

      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }

从上面可以看到 promoteCalls() 方法主要是在对异步就绪队列进行遍历 readyAsyncCalls,从中取出请求,并且将该请求添加到异步执行请求队列中,并通过线程池来进行执行,即executorService().execute(call;),直到异步执行队列中的任务数超过了最大请求数,便会退出。
同时如果当前分发器中,没有在等待的就绪请求,也没有正在执行的任务,便会使用Dispatcher 中的idleCallback 来进行当前任务的执行,其实就是执行一个runnable,(这里不太清楚)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值