1. 开启异步请求
通过OkHttpClient对象和Request,创建RealCall对象,调用RealCall的enqueue方法开启异步请求。代码如下:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://example.com")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// Handle failure
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// Handle response
}
});
2. 创建AsyncCall对象,将请求交给调度器
在enqueue方法中,创建AsyncCall对象,并将该对象交给调度器。代码如下:
@Override
public void enqueue(Callback responseCallback) {
// 检查是否重复调用enqueue方法
if (!executed.compareAndSet(false, true)) {
throw new IllegalStateException("Already Executed");
}
callStart();
// 调用dispatcher的enqueue方法,参数为AsyncCall对象
client.dispatcher.enqueue(new AsyncCall(responseCallback));
}
3. 调度器将异步请求加入队列
在分析Dispatcher的enqueue方法前,需要先了解下Dispatcher。它主要用于控制并发的请求,无论是同步请求还是异步请求,都会通过Dispatcher来处理。Dispatcher主要维护了以下变量:
class Dispatcher {
// 最大任务请求数
@Synchronized var maxRequests: Int = 64
// 每个主机的最大任务请求数
@Synchronized var maxRequestsPerHost: Int = 5
// 准备运行的异步请求队列
private val readyAsyncCalls = ArrayDeque<AsyncCall>()
// 正在运行的异步请求队列
private val runningAsyncCalls = ArrayDeque<AsyncCall>()
// 正在运行的同步请求队列
private val runningSyncCalls = ArrayDeque<RealCall>()
// 执行异步请求的线程池
private var executorServiceOrNull: ExecutorService? = null
// 获取或创建默认线程池
@get:Synchronized
@get:JvmName("executorService")
val executorService: ExecutorService
get() {
if (executorServiceOrNull == null) {
executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60L, TimeUnit.SECONDS,
SynchronousQueue(), threadFactory("OkHttp Dispatcher", false))
}
return executorServiceOrNull!!
}
// Dispatcher的构造方法,可以设定线程池
constructor(executorService: ExecutorService) {
this.executorServiceOrNull = executorService
}
}
它的enqueue方法将AsyncCall添加到准备运行的异步请求队列中readyAsyncCalls,然后调用promoteAndExecute方法,如下:
fun enqueue(call: AsyncCall) {
synchronized(this) {
readyAsyncCalls.add(call)
}
promoteAndExecute()
}
在promoteAndExecute方法中,会遍历readyAsyncCalls,如果符合条件则将AsyncCall从readyAsyncCalls中移除,并添加到runningAsyncCalls中,然后调用executeOn方法,开启异步任务。代码如下:
private fun promoteAndExecute() {
//记录可执行请求的AsyncCall
val executableCalls = ArrayList<AsyncCall>()
synchronized(this) {
//获取准备运行的异步请求队列的迭代器,然后开始遍历readyAsyncCalls
val iterator = readyAsyncCalls.iterator()
while (iterator.hasNext()) {
val asyncCall = iterator.next()
//如果正在运行的异步请求数大于或等于最大任务请求数,则直接结束循环
if (runningAsyncCalls.size >= maxRequests) break
//如果asyncCall中的主机数大于或等于同一主机的最大任务数,则跳过这个请求
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue
iterator.remove()
//记录可执行请求的AsyncCall
executableCalls.add(asyncCall)
//正在运行的异步请求队列
runningAsyncCalls.add(asyncCall)
}
}
for (asyncCall in executableCalls) {
//取出每个可执行的AsyncCall,调用其executeOn方法
asyncCall.executeOn(executorService)
}
}
4. AsyncCall开启异步任务
AsyncCall是RealCall的内部类,实现了Runnable接口,在其run方法中通过拦截器链得到网络响应,源码如下:
internal inner class AsyncCall(private val responseCallback: Callback) : Runnable {
fun executeOn(executorService: ExecutorService) {
client.dispatcher.executed(this@RealCall)
executorService.execute(this)
}
override fun run() {
try {
val response = getResponseWithInterceptorChain()
responseCallback.onResponse(this@RealCall, response)
} catch (e: IOException) {
responseCallback.onFailure(this@RealCall, e)
} finally {
client.dispatcher.finished(this)
}
}
}
可以看到,通过拦截器链得到网络响应后,无论响应成功还是失败,最终都会调用Dispatcher的finished方法,如下:
fun finished(call: AsyncCall) {
synchronized(this) {
runningAsyncCalls.remove(call)
}
promoteAndExecute()
}
当一个请求完成后调用该finished方法,移除当前AsyncCall并继续调用promoteAndExecute,处理下一个异步请求。
5. 拦截器链
拦截器链是OkHttp的核心逻辑,在AsyncCall的异步任务中,通过拦截器链来得到网络响应,即调用getResponseWithInterceptorChain方法。源码如下:
@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
// 创建拦截器集合
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方法主要处理了两件事:
- 创建拦截器集合,并将所有拦截器添加到集合中。
- 创建职责链,并启动它。
各拦截器作用
client.interceptors:应用拦截器,通过OkHttpClient设置。RetryAndFollowUpInterceptor:重试拦截器,负责网络请求中的重试和重定向。比如网络请求过程中出现异常,就会重试请求。BridgeInterceptor:桥接拦截器,用于桥接应用层和网络层的请求数据。请求时将应用层的数据类型转换为网络层的数据类型,响应时则将网络层返回的数据类型转换为应用层的数据类型。CacheInterceptor:缓存拦截器,负责读取和更新缓存。可以配置自定义的缓存拦截器。ConnectInterceptor:网络连接拦截器,其内部会获取一个连接。client.networkInterceptors:网络连接拦截器,通过OkHttpClient设置。CallServerInterceptor:请求服务拦截器。拦截器链中处于末尾的拦截器,用于向服务器发送数据并获取响应。
职责链
职责链采用职责链模式,使得每个拦截器都有机会处理请求,这些拦截器形成了拦截器链。网络请求经过拦截器链的处理然后发送出去;同样,网络响应也经过拦截器的处理返回给应用层。职责链启动方式如下:
@Throws(IOException::class)
override fun proceed(request: Request): Response {
check(index < interceptors.size)
calls++
if (exchange != null) {
check(exchange.finder.sameHostAndPort(request.url)) {
"network interceptor ${interceptors[index - 1]} must retain the same host and port"
}
check(calls == 1) {
"network interceptor ${interceptors[index - 1]} must call proceed() exactly once"
}
}
// 调用RealInterceptorChain的copy方法,其内部会创建一个RealInterceptorChain,
// 通过参数index+1来循环处理inter
ceptors中的拦截器
val next = copy(index = index + 1, request = request)
// 获取当前要执行的拦截器
val interceptor = interceptors[index]
// 运行当前的拦截器,并设置了下一个拦截器。
// 其内部逻辑是,当前拦截器处理完成后,会接着执行下一个拦截器的proceed方法
@Suppress("USELESS_ELVIS")
val response = interceptor.intercept(next) ?: throw NullPointerException(
"interceptor $interceptor returned null")
if (exchange != null) {
check(index + 1 >= interceptors.size || next.calls == 1) {
"network interceptor $interceptor must call proceed() exactly once"
}
}
check(response.body != null) { "interceptor $interceptor returned a response with no body" }
return response
}
通过以上代码,可以看到每个拦截器在职责链中的位置,通过proceed方法依次调用下一个拦截器,直到最后一个拦截器处理请求并返回响应。