这里有三个主要的类需要说明一下:OkHttpClient、Request以及RealCall。
-
OkHttpClient: 相当于配置中⼼,可用于发送 HTTP 请求并读取其响应。它的配置有很多,例如connectTimeout:建⽴连接(TCP 或 TLS)的超时时间,readTimeout :发起请求到读到响应数据的超时时间,Dispatcher:调度器,⽤于调度后台发起的⽹络请求,等等。还有其他配置可查看源码。
-
Request: 一个主要设置网络请求Url、请求方法(GET、POST…)、请求头、请求body的请求类。
-
RealCall: RealCall是由newCall(Request)方法返回,是OkHttp执行请求最核心的一个类之一,用作连接OkHttp的应用程序层和网络层,也就是将OkHttpClient和Request结合起来,发起异步和同步请求。
从上面的使用步骤可以看到,OkHttp最后执行的是okHttpClient.newCall(request).enqueue
,也就是RealCall的enqueue方法,这是一个异步请求,同样的,也可以执行同步请求RealCall.execute()
。
RealCall的同步请求最后其实会调用RealCall.getResponseWithInterceptorChain()
,而RealCall的异步请求是使用线程池先将请求放置到后台处理,但是最后还是会调用RealCall.getResponseWithInterceptorChain()
来获取网络请求的返回值Response。从这里就基本能嗅到网络请求的核心其实与getResponseWithInterceptorChain()方法有关,那到底如何与服务器连接进行网络请求的?这个问题就先抛在这,后面再详细说。
我们先从异步请求enqueue开始,来看异步请求的主要结构。
类:Dispatcher
private fun promoteAndExecute(): Boolean {
…
val executableCalls = mutableListOf()
synchronized(this) {
val i = readyAsyncCalls.iterator()
while (i.hasNext()) {
val asyncCall = i.next()
if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
i.remove()
asyncCall.callsPerHost.incrementAndGet()
executableCalls.add(asyncCall)
runningAsyncCalls.add(asyncCall)
}
isRunning = runningCallsCount() > 0
}
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)
}
return isRunning
}
异步请求首先会将AsyncCall添加到双向队列readyAsyncCalls中(即准备执行但还没有执行的队列),做请求的准备动作。接着遍历准备执行队列readyAsyncCalls,寻找符合条件的请求,并将其加入到一个保存有效请求的列表executableCalls和正在执行队列runningAsyncCalls中,而这个筛选条件主要有两条:
-
if (runningAsyncCalls.size >= this.maxRequests) break
:并发执行的请求数要小于最大的请求数64。 -
if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue
:某个主机的并发请求数不能超过最大请求数5
也就是说,当我们的并发请求量超过64个或者某个主机的的请求数超过5,则超过的请求暂时不能执行,需要等一等才能再加入执行队列中。
将有效的请求筛选出后并保存,立即开始遍历请求,一一利用调度器Dispatcher里的ExecutorService进行Runnable任务,也就是遍历后加入到线程池中执行这些有效的网络请求。
类:RealCall.AsyncCall
override fun run() {
threadName(“OkHttp ${redactedUrl()}”) {
…
try {
val re