【OkHttp】源码分析

OkHttp源码分析

在这里插入图片描述

前言

OkHttp是由Square公司贡献的一个处理网络请求的开源项目,是目前Android使用最广泛的网络请求框架。

从Android4.4开始,HttpURLConnnection的底层实现也开始采用OkHttp了。

那么,OkHttp有哪些特性呢?

  • 支持HTTP/2并允许对同一个主机的所有请求共享一个套接字
  • 如果非HTTP/2,则通过连接池,减少了请求延迟
  • 默认请求GZip压缩数据
  • 响应缓存,避免了重复请求的网络

本文重点,深入OkHttp源码,对OkHttp的整体流程进行分析,对分发器Dispatcher的处理流程进行详细分析。

好了,那就进入整体吧!

基本使用

OkHttp的使用非常简单,我们来看看它是怎么使用的:

1、导入依赖:
api 'com.squareup.okhttp3:okhttp:3.10.0'

2、基本使用:
val mOkHttpClient: OkHttpClient = OkHttpClient()
val request: Request = Request.Builder().url(url).build()
val call: Call = mOkHttpClient.newCall(request)

//执行同请求
val response: Response = call.execute()

//执行异步请求
call.enqueue(object : Callback {
    override fun onFailure(call: Call, e: IOException) {
        TODO("Not yet implemented")
    }

    override fun onResponse(call: Call, response: Response) {
        TODO("Not yet implemented")
    }

})

1、首先需要构建出一个OkHttpClient对象,我们可以选择直接调用它的无参构造方法构建。另外,也可使用它内部的Builder对象,根据自己的需求来构建OkHttpClient对象,如:

val mOkHttpClient: OkHttpClient = OkHttpClient.Builder()
                                              .addInterceptor(MyInterceptor())
                                              .dispatcher(MyDispatcher())
                                              .build()

2、通过Request.Builder()构建出一个Request对象

3、通过mOkHttpClient.newCall(request)构建出一个Call对象(实际上是RealCall对象)

4、执行同步请求call.execute() 或 异步请求call.enqueue(Callback responseCallback)

整体流程分析(基于3.10.0的源码)

OkHttpClient对象的构建

我们先从OkHttpClient的构造方法开始看起,它有两个构造方法,如下:

1public OkHttpClient()
2OkHttpClient(Builder builder)

可见,一个是public的无参构造方法,一个私有的有参构造方法,我们进入public OkHttpClient()

OkHttpClient.java:
public OkHttpClient() {
  this(new Builder());
}

它的内部又调用了私有构造方法,并传了一个Builder对象进去,那么我们就继续进入Builder构造方法看看:

OkHttpClient.Builder:
public Builder() {
  dispatcher = new Dispatcher();
  protocols = DEFAULT_PROTOCOLS;
  connectionSpecs = DEFAULT_CONNECTION_SPECS;
  eventListenerFactory = EventListener.factory(EventListener.NONE);
  proxySelector = ProxySelector.getDefault();
  cookieJar = CookieJar.NO_COOKIES;
  socketFactory = SocketFactory.getDefault();
  hostnameVerifier = OkHostnameVerifier.INSTANCE;
  certificatePinner = CertificatePinner.DEFAULT;
  proxyAuthenticator = Authenticator.NONE;
  authenticator = Authenticator.NONE;
  connectionPool = new ConnectionPool();
  dns = Dns.SYSTEM;
  followSslRedirects = true;
  followRedirects = true;
  retryOnConnectionFailure = true;
  connectTimeout = 10_000;
  readTimeout = 10_000;
  writeTimeout = 10_000;
  pingInterval = 0;
}

这里主要就是对OkHttpClient.Builder类中一些成员变量进行了初始化,例如分发器Dispatcher就是这里初始化的,注意,这里的分发器对象是Builder类的成员变量。

我们继续回到OkHttpClient的构造方法中,进入它的私有构造方法看看:

OkHttpClient.java:
OkHttpClient(Builder builder) {
  this.dispatcher = builder.dispatcher;
  this.proxy = builder.proxy;
  this.protocols = builder.protocols;
  this.connectionSpecs = builder.connectionSpecs;
  this.interceptors = Util.immutableList(builder.interceptors);
  this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
  this.eventListenerFactory = builder.eventListenerFactory;
  this.proxySelector = builder.proxySelector;
  this.cookieJar = builder.cookieJar;
  this.cache = builder.cache;
  this.internalCache = builder.internalCache;
  this.socketFactory = builder.socketFactory;
  ....................................................................................
  this.hostnameVerifier = builder.hostnameVerifier;
  this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
      certificateChainCleaner);
  this.proxyAuthenticator = builder.proxyAuthenticator;
  this.authenticator = builder.authenticator;
  this.connectionPool = builder.connectionPool;
  this.dns = builder.dns;
  this.followSslRedirects = builder.followSslRedirects;
  this.followRedirects = builder.followRedirects;
  this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
  this.connectTimeout = builder.connectTimeout;
  this.readTimeout = builder.readTimeout;
  this.writeTimeout = builder.writeTimeout;
  this.pingInterval = builder.pingInterval;

  if (interceptors.contains(null)) {
    throw new IllegalStateException("Null interceptor: " + interceptors);
  }
  if (networkInterceptors.contains(null)) {
    throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
  }
}

可以看到,这个方法的操作基本就是将OkHttpClient.Builder类的成员变量赋值给OkHttpClient类对应的成员变量中。

这种构造方式就是典型的建造者模式。

通过OkHttpClient.Builder类,我们可以根据自己的需求构建出想要的OkHttpClient对象:

val mOkHttpClient: OkHttpClient = OkHttpClient.Builder()
										  .dispatcher(MyDispatcher()) // 设置自己的分发器
										  .addInterceptor(MyInterceptor) // 添加自定义的拦截器
										  .build()

当然,如果我们直接通过OkHttpClient()的方法创建OkHttpClient对象,通过刚刚分析的源码也可以知道,会使用默认的规则来构建。

Request对象的构建

而对于Request对象,它的内部没有public的构造方法,仅有一个私有的构造方法,同时,它跟OkHttpClient类一样,也使用了建造者模式,因此,Request对象只能通过建造者模式的方式来构建,如:

val request: Request = Request.Builder().url(url).build()

Call对象的构建

在使用时,我们是通过这样的方式来构建的Call对象的:

val call: Call = mOkHttpClient.newCall(request)

那么,我们进入OkHttpClient的newCall方法看看:

OkHttpClient.java:
@Override public Call newCall(Request request) {
  return RealCall.newRealCall(this, request, false /* for web socket */);
}

它调用了RealCallnewRealCall方法,那么我们跟进看看:

RealCall.java:
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
  // Safely publish the Call instance to the EventListener.
  RealCall call = new RealCall(client, originalRequest, forWebSocket);
  call.eventListener = client.eventListenerFactory().create(call);
  return call;
}

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

在newRealCall方法中,分为以下三个步骤:

1、构建了一个RealCall对象call,在RealCall的构造方法中,可以看到重试和重定向拦截器在这里被创建

2、然后将call的eventListener进行了赋值,即为请求设置了监听。当然,eventListener赋值不为null的前提是我们在构建OkHttpClient的时,通过eventListenerFactory方法传递了一个eventListenerFactory对象。

3、最后将RealCall对象返回

同步请求

我们在使用的时候,只需要通过call.execute()这行代码,就完成了同步请求,而从刚刚Call对象的构建的源码中,我们也知道了,这个call其实就是RealCall,那么execute方法内部到底做了什么呢?

我们进入RealCall的execute方法看看:

RealCall.java:
@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);
  }
}

它做了以下几件事情:

1、如果请求已被执行,则抛出异常,这里也可以看出,一个call只能执行一次请求

2、将RealCall的executed变量置为true

3、执行eventListener.callStart(this);告诉监听者请求已开始

4、执行分发器的executed方法

5、执行拦截器,得到Response对象,即得到请求的结果,然后将Response返回

6、如果请求过程中出错,则eventListener回调请求错误

7、最后调用dispatcher的finished(RealCall call)方法

我们继续跟进第3步,看看分发器的executed方法做了什么:

Dispatcher.java:
synchronized void executed(RealCall call) {
  runningSyncCalls.add(call);
}

它被synchronized关键字修饰,说明它的操作是线程安全的,且内部仅仅只做了一件事,就是将call添加到runningSyncCalls集合中。因为同步请求不需要使用到线程池,也不存在其他限制,所以在这里分发器仅做一下记录,将这个call添加到runningSyncCalls集合中。

那么runningSyncCalls是什么呢?它表示正在执行的同步请求队列,它存放的是RealCall(实现Call接口)对象。

其实对应的,还有readyAsyncCalls和readyAsyncCalls,我们看看它们的定义:

  Dispatcher.java:  
  // 等待请求的异步请求队列,存放的是AsyncCall(实现Runnable)对象
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  // 正在执行的异步请求队列,存放的是AsyncCall(实现Runnable)对象
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  // 正在执行的同步请求队列,存放的是RealCall(实现Call接口)对象
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

可以看到,三个队列都是ArrayDeque实现的,ArrayDeque实际上是一个双端队列。

我们继续回到RealCall.execute()方法的第4步,看看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());
  }
  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);
}

这个方法实际上就是构建了一个集合interceptors,并将拦截器添加到这个集合中,这里我们注意一下,拦截器的添加顺序是

  • 首先添加在OkHttpClient中由我们自定义的普通拦截器
  • 然后是retryAndFollowUpInterceptor-重试和重定向拦截器
  • 然后是BridgeInterceptor-桥接拦截器
  • 然后是CacheInterceptor-缓存拦截器
  • 然后是ConnectInterceptor-连接拦截器
  • 然后是在OkHttpClient中由我们自定义的网络拦截器
  • 最后是CallServerInterceptor-响应网络的拦截器

当添加完拦截器后,就构造出一条责任链chain,并执行chain.proceed(originalRequest)方法执行请求,然后得到响应的结果。拦截器相关的知识其实是OkHttp的核心,它拦截器的内容也比较多,后续我会出一个专门讲拦截器知识的的文章,这里篇幅有限,就不在这写了。

我们继续回到RealCall.execute()方法的第最后一步,看看Dispatcher的finished方法做了什么:

Dispatcher.java:
void finished(RealCall call) {
  finished(runningSyncCalls, call, false);
}

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      // promoteCalls为false,因此promoteCalls()不会执行
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

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

finished方法内部又调用了finished方法,可以看到,还执行了calls.remove(call)方法将这个call对象从runningSyncCalls队列中移除,另外,由于finished方法的第三个参数传入了false,因此promoteCalls()方法不会执行。

异步请求

通过RealCall.enqueue(Callback responseCallback)这行代码,就可以完成了异步请求。我们进入RealCall的enqueue方法看看它做了什么:

RealCall.java:
@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));
}

可以看到,如果请求已被执行,则抛出异常(一个call只能执行一次请求),这个判断跟同步请求那里是一样的。

方法的最后执行了dispatcher的enqueue方法,并传入了一个AsyncCall对象。

我们先来看AsyncCall是什么东西,看它是怎么定义的:

RealCall.java:
final class AsyncCall extends NamedRunnable {
  private final Callback responseCallback;

  AsyncCall(Callback responseCallback) {
    super("OkHttp %s", redactedUrl());
    // 将外部传入的responseCallback赋值给自己的成员变量responseCallback
    this.responseCallback = responseCallback;
  }
  ...................................................................
  // 这个execute方法会在Runnable被执行的时候调用
  @Override protected void execute() {
    boolean signalledCallback = false;
    try {
      // 通过拦截器得到响应的Response对象
      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 {
      // 最后调用dispatcher的finished
      client.dispatcher().finished(this);
    }
  }
}

可以看到,它继承自NamedRunnable类,而NamedRunnable,实际上是个Runnable。

然后我们看它的构造方法,将外部传入的responseCallback赋值给自己的成员变量responseCallback,

然后我们重点看它的execute方法,execute方法会在Runnable被执行的时候调用。它做了以下几件事:

1、通过拦截器得到响应的Response对象

2、如果重试和重定向拦截器被取消,则回调失败

3、如果重试和重定向拦截器没有被取消,则回调成功

4、最后调用dispatcher的finished(AsyncCall call)方法

是不是很熟悉,在分析同步请求的时候,我们也看到了类似的代码,而这里最后调用dispatcher的finished方法稍有不同,我们进去看看:

void finished(AsyncCall call) {
  finished(runningAsyncCalls, call, true);
}

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    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方法的时候,第三个参数传了一个true(同步请求的时候,这个参数传的false)。

因此,它会执行promoteCalls()方法,我们进入promoteCalls()方法看看:

private void promoteCalls() {
  // 如果正在执行的异步请求的个数大于maxRequests(64),直接return
  if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
  // 如果没有等待执行的异步请求的个数,直接return
  if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
  // 遍历正在执行的异步请求队列
  for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
    AsyncCall call = i.next();
    // 如果正在执行的相同域名的请求的个数小于maxRequestsPerHost(5)
    if (runningCallsForHost(call) < maxRequestsPerHost) {
      // 将这个异步请求从等待请求的队列中移除
      i.remove();
      // 将这个异步请求添加到正在执行的异步请求队列中
      runningAsyncCalls.add(call);
      // 通过线程池执行这个请求
      executorService().execute(call);
    }
    // 每次循环结束都检查一遍如果正在执行的异步请求的个数大于maxRequests(64),直接return
    if (runningAsyncCalls.size() >= maxRequests) return;
  }
}

方法的流程我在注释中已经写得很清楚了,这里我用一句话概括这个方法做的事情:从等待执行的异步请求队列readyAsyncCalls中取出请求(如果有),放到正在执行的异步请求队列runningAsyncCalls中,并通过线程池执行。

另外,这里有两个变量要知道它们大概是什么意思:

  • maxRequests:表示正在执行的异步请求个数的最大值,默认值是64,且可以通过setMaxRequests方法自定义个数
  • maxRequestsPerHost:表示相同域名异步请求个数的最大值,默认值是5,且可以通过setMaxRequestsPerHost方法自定义个数

好了,我们继续回到RealCall的enqueue方法:

RealCall.java:
@Override public void enqueue(Callback responseCallback) {
  ...........................................................
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

方法的最后执行了dispatcher的enqueue方法,我们进入dispatcher的enqueue方法看看:

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

这里有个判断条件,如果runningAsyncCalls(正在执行的异步请求队列)的size小于maxRequests,且runningCallsForHost(call)小于maxRequestsPerHost,则将call添加到runningAsyncCalls队列中,然后通过线程池执行这个call,否则就添加到readyAsyncCalls中等待执行(等待请求的异步请求队列)。

Dispatcher-分发器

在上面的流程分析中,我们一定有关注到一个类,那就是Dispatcher类,这个类也叫分发器,,它的作用是对请求进行分发。我们先看下Dispatcher类中的几个成员变量:

Dispatcher.java:
// 正在执行的异步请求个数的最大值
private int maxRequests = 64;
// 相同域名的异步请求个数的最大值
private int maxRequestsPerHost = 5;
// 一般用不到的一个变量(没有请求时可以执行的一些任务,可以由调用者传入进来)
private @Nullable Runnable idleCallback;
// 分发器的线程池,有默认实现,也可自定义传入
private @Nullable ExecutorService executorService;
// 等待请求的异步请求队列,存放的是AsyncCall(实现Runnable)对象
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
// 正在执行的异步请求队列,存放的是AsyncCall(实现Runnable)对象
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
// 正在执行的同步请求队列,存放的是RealCall(实现Call接口)对象
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

首先看到第四个成员变量executorService,它是Dispatcher的线程池我们看下它是怎么定义的:

Dispatcher.java:
public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

可以看出,一个核心线程数为0,非核心线程数无限大,线程保活时间60S,使用SynchronousQueue缓存任务的线程池。

SynchronousQueue是怎样的数据结构呢?它又叫无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者,必须等队列中添加的元素被消费后才能继续添加新的元素。它可以使每个任务都会被顺序执行。

下面我们重点分析Dispatcher的三个队列:

  • readyAsyncCalls:等待请求的异步请求队列,存放的是AsyncCall(实现Runnable)对象
  • runningAsyncCalls:正在执行的异步请求队列,存放的是AsyncCall(实现Runnable)对象
  • runningSyncCalls:正在执行的同步请求队列,存放的是RealCall(实现Call接口)对象

在上面的篇幅中,我们分析OkHttp流程的源码的流程中,我们已经知道

  • 执行同步请求时,会走到client.dispatcher().executed(this)方法
  • 执行异步请求时,会走到client.dispatcher().enqueue(new AsyncCall(responseCallback))方法

那么我们看看这两个方法做了什么:

Dispatcher.java:
//同步请求
synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
}

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

首先看到它们都被synchronized关键字修饰,说明它的操作是线程安全的。

executed(RealCall call)方法且内部仅仅只做了一件事,就是将RealCall对象添加到runningSyncCalls集合中。因为同步请求不需要使用到线程池,也不存在其他限制,所以在这里分发器仅做一下记录,将这个RealCall添加到runningSyncCalls集合中。

enqueue(AsyncCall call)方法的逻辑也很简单,有个判断条件,如果runningAsyncCalls(正在执行的异步请求队列)的size小于maxRequests,且runningCallsForHost(call)小于maxRequestsPerHost,则将call添加到runningAsyncCalls队列中,然后通过线程池执行这个call,否则就添加到readyAsyncCalls中等待执行(等待请求的异步请求队列)。

至此,我们已经知道分发器是如何决定将不同类型的任务放到不同的请求队列上了。

那么,还有个问题:【等待请求的异步请求队列】上的任务是怎么添加到【正在执行的异步请求队列】的呢?它又是什么时候执行的呢?

我们回想一下上面分析OkHttp流程的源码:

  • 执行同步请求时,即执行RealCall.execute()方法时,方法的最后调用了client.dispatcher().finished(this)方法
  • 执行异步请求时,即执行RealCall.enqueue(Callback responseCallback)方法,会通过线程池执行AsyncCall对象的execute方法,这execute方法最后,则会调用client.dispatcher().finished(this)方法

所以,我们跟进Dispatcher的finished方法看看做了什么:

Dispatcher.java:
// 当任务是AsyncCall(异步任务)时,调用这个finished
void finished(AsyncCall call) {
  finished(runningAsyncCalls, call, true);
}

// 当任务是同步任务时,调用这个finished
void finished(RealCall call) {
  finished(runningSyncCalls, call, false);
}

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
  int runningCallsCount;
  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方法时,第三个参数传了一个true(同步请求的时候,这个参数传的false)。finished方法会执行calls.remove(call)方法将任务从对应的任务队列中移除。

当任务是异步任务的时候,它还会执行promoteCalls()方法(因为第三个参数为true),那么我们进入promoteCalls()方法看看:

private void promoteCalls() {
  // 如果正在执行的异步请求的个数大于maxRequests(64),直接return
  if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
  // 如果没有等待执行的异步请求的个数,直接return
  if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
  // 遍历正在执行的异步请求队列
  for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
    AsyncCall call = i.next();
    // 如果正在执行的相同域名的请求的个数小于maxRequestsPerHost(5)
    if (runningCallsForHost(call) < maxRequestsPerHost) {
      // 将这个异步请求从等待请求的队列中移除
      i.remove();
      // 将这个异步请求添加到正在执行的异步请求队列中
      runningAsyncCalls.add(call);
      // 通过线程池执行这个请求
      executorService().execute(call);
    }
    // 每次循环结束都检查一遍如果正在执行的异步请求的个数大于maxRequests(64),直接return
    if (runningAsyncCalls.size() >= maxRequests) return;
  }
}

方法的流程我在注释中已经写得很清楚了,这里我用一句话概括这个方法做的事情:从等待执行的异步请求队列readyAsyncCalls中取出请求(如果有),放到正在执行的异步请求队列runningAsyncCalls中,并通过线程池执行该call。

至此,我们已经可以回答这个问题:【等待请求的异步请求队列】上的任务是怎么添加到【正在执行的异步请求队列】的呢?它又是什么时候执行的呢?

答:在执行完异步请求后,会执行dispatcher的finished方法,将执行完毕的异步请求call从【正在执行的异步请求队列】中移除,然后还会执行promoteCalls()方法,从【等待请求的异步请求队列】中取出请求call(如果有),放到【正在执行的异步请求队列】中,然后通过线程池执行该call。

拦截器

拦截器的内容比较多,后续我会出一个专门讲拦截器知识的的文章,这里篇幅有限,就不在这写了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一场雪ycx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值