OkHttp中,异步请求的调用步骤一般如下:
```
val okHttpClient = OkHttpClient.Builder().build()
val request = Request.Builder()
.url("https://www.baidu.com/").build()
val call = okHttpClient.newCall(request)
call.enqueue(object : Callback{
override fun onFailure(call: Call, e: IOException) {
println(e.message)
}
override fun onResponse(call: Call, response: Response) {
println(response.body)
}
})
```
RealCall
```
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
```
newCall(request)方法生成一个RealCall对象,RealCall实现了Call接口,call可以理解成准备好执行的请求,一个Call只能执行一次,它提供了请求相关的方法如同步请求execute()、异步请求enqueue(responseCallback)、取消请求cancel()、以及获取请求的状态isExecuted()、isCanceled()等。
Dispatcher
```
override fun enqueue(responseCallback: Callback) {
check(executed.compareAndSet(false, true)) { "Already Executed" }
callStart()
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
readyAsyncCalls.add(call)
if (!call.call.forWebSocket) {
val existingCall = findExistingCallWithHost(call.host)
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
}
}
promoteAndExecute()
}
```
RealCall的enqueue方法调用了Dispatcher的enqueue方法,并传递了AsyncCall,AsyncCall是RealCall的内部类。
对于异步请求,Dispatcher提供了两个队列readyAsyncCalls和runningAsyncCalls,分别存储准备好的Call和正在执行的Call,在enqueue方法中首先就是把AsyncCall放入readyAsyncCalls中。
AsyncCall中有一个属性callsPerHost,表示当前连接host的数量,如果call要请求的host相同,它们的callsPerHost值是共享的,具体实现就在findExistingCallWithHost和call.reuseCallsPerHostFrom(existingCall)处,逻辑就是在readyAsyncCalls和runningAsyncCalls中寻找和当前call的host一致的其他call,把其他call的callsPerHost赋值给当前call。
```
private fun promoteAndExecute(): Boolean {
this.assertThreadDoesntHoldLock()
val executableCalls = mutableListOf<AsyncCall>()
val isRunning: Boolean
synchronized(this) {
val i = readyAsyncCalls.iterator()
while (i.hasNext()) {
val asyncCall = i.next()
if (runningAsyncCalls.size >= this.maxRequests) break
if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue 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
}
```
promoteAndExecute()方法中,当readyAsyncCalls中有数据时,需要做两个判断:1.runningAsyncCalls(当前正在执行的请求)需要小于maxRequests(64);2.单个host同一时刻的请求数量最多不能超过maxRequestsPerHost(5)。这两项满足后,将AsyncCall从readyAsyncCalls中取出放入runningAsyncCalls,同时使用线程池执行asyncCall,AsyncCall实现了Runnable接口。
```
@get:JvmName("executorService") val executorService: ExecutorService
get() {
if (executorServiceOrNull == null) {
executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
}
return executorServiceOrNull!!
}
```
executorService的核心线程数是0,最大线程数无限制,说明只要有请求过来就会创建线程立即执行,不会等待。由于前面有runningAsyncCalls<=64的限制,这里创建的线程数量也是有限的。
AsyncCall
override fun run() {
threadName("OkHttp ${redactedUrl()}") {
var signalledCallback = false
timeout.enter()
try {
val response = getResponseWithInterceptorChain()
signalledCallback = true
responseCallback.onResponse(this@RealCall, response)
} catch (e: IOException) {
if (signalledCallback) {
Platform.get().log("Callback failure for ${toLoggableString()}", Platform.INFO, e)
} else {
responseCallback.onFailure(this@RealCall, e)
}
} catch (t: Throwable) {
cancel()
if (!signalledCallback) {
val canceledException = IOException("canceled due to $t")
canceledException.addSuppressed(t)
responseCallback.onFailure(this@RealCall, canceledException)
}
throw t
} finally {
client.dispatcher.finished(this)
}
}
}
}
AsyncCall的run方法核心就是getResponseWithInterceptorChain(),这里使用责任链模式,通过多个拦截器处理request,结果通过responseCallback传递给调用者。