OkHttp分为异步请求和同步请求两部分
同步请求
vbscript
call.execute()
execute
代码如下:
#okhttp3.internal.connection.RealCall
kotlin
override fun execute(): Response {
check(executed.compareAndSet(false, true)) { "Already Executed" }
// 1.开启超时检测
timeout.enter()
callStart()
try {
// 2. 将请求添加在同步请求队列
client.dispatcher.executed(this)
//3. 调用getResponseWithInterceptorChain获取Response
return getResponseWithInterceptorChain()
} finally {
client.dispatcher.finished(this)
}
}
-
开启超时检测
-
将请求添加在同步请求队列
-
调用
getResponseWithInterceptorChain
获取Response
异步请求
okHttpClient.newCall
返回值
首先,我们看一下okHttpClient.newCall
返回的是什么
vbscript
newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
newCall
返回一个RealCall
对象
call.enqueue
的源码
kotlin
override fun enqueue(responseCallback: Callback) {
check(executed.compareAndSet(false, true)) { "Already Executed" }
//1.
callStart()
//2.
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
callStart()
方法,内部调用的EventListener.callStart
,是一个全局监听请求过程的方法- 调用
dispatcher
的enqueue
方法,从字面理解为,请求需要排队执行,这里的请求是AsyncCall
对象,AsyncCall
中包含返回结果的监听responseCallback
,也就是我们在调用call.enqueue
时传入的callBack
。
AsyncCall下面会进行具体介绍
Dispatcher的enqueue方法
scss
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
//1.
readyAsyncCalls.add(call)
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
if (!call.call.forWebSocket) {
val existingCall = findExistingCallWithHost(call.host)
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
}
}
//2.
promoteAndExecute()
}
使用同步锁*synchronized
*防止线程同步问题:
-
将
AsyncCall
对象加入readyAsyncCalls
这个队列中 -
promoteAndExecute()
,推动并执行,我们看一下具体干了什么
Dispatcher的promoteAndExecute方法
通过注释,我们可以很清楚的知道该函数的作用:
将合法的请求从readyAsyncCalls
队列里移到runningAsyncCalls
队列里,并且用ExecutorService
执行他们
kotlin
/**
* Promotes eligible calls from [readyAsyncCalls] to [runningAsyncCalls] and runs them on the
* executor service. Must not be called with synchronization because executing calls can call
* into user code.
*
* @return true if the dispatcher is currently running calls.
*/
private fun promoteAndExecute(): Boolean {
this.assertThreadDoesntHoldLock()
//1.
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 // Max capacity.
if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
// 从readyAsyncCalls中移除
i.remove()
asyncCall.callsPerHost.incrementAndGet()
//2. 添加到executableCalls/runningAsyncCalls 队列中
executableCalls.add(asyncCall)
runningAsyncCalls.add(asyncCall)
}
isRunning = runningCallsCount() > 0
}
// Avoid resubmitting if we can't logically progress
// particularly because RealCall handles a RejectedExecutionException
// by executing on the same thread.
if (executorService.isShutdown) {
...
} else {
for (i in 0 until executableCalls.size) {
// 3.
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)
}
}
return isRunning
}
- 声明一个
AsyncCall
的集合 - 将每个
AsynCall
从readyAsyncCalls
中移除,添加到executableCalls/runningAsyncCalls
队列中 - 从
executableCalls
中取出AsynCall
,调用AsyncCall.executeOn
方法,并传入executorService
executorService
为ExecutorService
对象:
kotlinval executorService: ExecutorService get() { if (executorServiceOrNull == null) { executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS, SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false)) } return executorServiceOrNull!! }
ExecutorService
是一个没有核心线程,非核心线程数为Int最大值,线程闲置60s会被回收的线程池
AsyncCall.executeOn
kotlin
fun executeOn(executorService: ExecutorService) {
client.dispatcher.assertThreadDoesntHoldLock()
var success = false
try {
//1.
executorService.execute(this)
success = true
} catch (e: RejectedExecutionException) {
failRejected(e)
} finally {
if (!success) {
client.dispatcher.finished(this) // This call is no longer running!
}
}
}
使用传入的executorService
线程池执行AsyncCall
任务,而AsyncCall
是一个Runnable
对象,直接查看其run方法
AsyncCall.run
kotlin
override fun run() {
threadName("OkHttp ${redactedUrl()}") {
var signalledCallback = false
// 1.
timeout.enter()
try {
// 2.
val response = getResponseWithInterceptorChain()
signalledCallback = true
// 3.
responseCallback.onResponse(this@RealCall, response)
} catch (e: IOException) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log("Callback failure for ${toLoggableString()}", Platform.INFO, e)
} else {
//4.
responseCallback.onFailure(this@RealCall, e)
}
} catch (t: Throwable) {
cancel()
if (!signalledCallback) {
val canceledException = IOException("canceled due to $t")
canceledException.addSuppressed(t)
// 5.
responseCallback.onFailure(this@RealCall, canceledException)
}
throw t
} finally {
client.dispatcher.finished(this)
}
}
}
-
调用
timeout.enter()
开启超时检测 -
调用
getResponseWithInterceptorChain
获取响应结果 -
获取到
response
后调用responseCallback.response
方法 -
调用
responseCallback.onFailure
,失通知败结果
getResponseWithInterceptorChain源码分析
ini
internal fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
val interceptors = mutableListOf<Interceptor>()
interceptors += client.interceptors
interceptors += RetryAndFollowUpInterceptor(client)
interceptors += BridgeInterceptor(client.cookieJar)
interceptors += CacheInterceptor(client.cache)
interceptors += ConnectInterceptor
if (!forWebSocket) {
interceptors += client.networkInterceptors
}
interceptors += CallServerInterceptor(forWebSocket)
val chain = RealInterceptorChain(
call = this,
interceptors = interceptors,
index = 0,
exchange = null,
request = originalRequest,
connectTimeoutMillis = client.connectTimeoutMillis,
readTimeoutMillis = client.readTimeoutMillis,
writeTimeoutMillis = client.writeTimeoutMillis
)
var calledNoMoreExchanges = false
try {
val response = chain.proceed(originalRequest)
if (isCanceled()) {
response.closeQuietly()
throw IOException("Canceled")
}
return response
} catch (e: IOException) {
calledNoMoreExchanges = true
throw noMoreExchanges(e) as Throwable
} finally {
if (!calledNoMoreExchanges) {
noMoreExchanges(null)
}
}
}
简单来说,getResponseWithInterceptorChain
方法中,就是构建一个链式拦截器,然后发起请求,整个过程是通过拦截器的链式调用完成的,即先从左到右调用,再从右到左返回结果
暂时无法在飞书文档外展示此内容
-
RetryAndFollowUpInterceptor
:负责失败重试和重定向 -
BridgeInterceptor
:负责把用户请求转换为发送到服务器的请求,并把服务器的响应转化为用户需要的响应 -
CacheInterceptor
:负责读取缓存、更新缓存 -
ConnectInterceptor
:负责和服务器建立连接 -
CallServerInterceptor
:负责向服务器发送数据,从服务器读取响应数据
addInterceptor 和 addNetworkInterceptor区别
在getResponseWithInterceptorChain
方法中可以看到:拦截器是通过责任链模式调用的,
addInterceptor
添加的Interceptor
会被添加到责任链的开端,因此:
-
任何情况下都会首先执行
-
不受重定向和重试机制的影响,即自定义拦截器只会被执行一次
addNetworkInterceptor
添加的拦截器处在ConnectInterceptor
之后,因此:
- 如果无网连接失败,该拦截器不会被调用
- 重定向和重试几次,该拦截器就会被调用几次
- 允许操作中间响应,比如当请求操作发生重定向(拦截被执行了两次)或者重试等。
- 不允许调用缓存来short-circuit (短路)这个请求。(意思就是说不能从缓存池中获取缓存对象返回给客户端,必须通过请求服务的方式获取响应,也就是Chain.proceed())
- 可以监听数据的传输