首先看一下OkHttp是怎样使用的,
- 同步请求 通过execute方法执行
fun requestSync() {
val request = Request.Builder()
.url("https://www.baidu.com")
.build()
val client = OkHttpClient.Builder()
.build()
val call = client.newCall(request)
val response = call.execute()
println("同步请求")
println(response.body?.string())
}
- 异步请求 通过enqueue方法执行
fun requestASync() {
val request = Request.Builder()
.url("https://www.baidu.com")
.build()
val client = OkHttpClient.Builder()
.build()
val call = client.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
}
override fun onResponse(call: Call, response: Response) {
println("异步请求")
println(response.body?.string())
}
})
}
可以看到不论是同步还是异步的方式,都是通过OkHttpClient创建一个Call,再通过Call执行网络请求,所以先从OkHttpClient开始分析。
OkHttpClient
首先看下OkHttpClient是怎样创建的,通过上面的代码很容易看出,OkHttpClient的创建使用的是建造者模式,设置一系列参数,最后通过OkHttpClient.Builder的build方法来构造返回OkHttpClient。通过源码可以验证
open class OkHttpClient internal constructor(
builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {
@get:JvmName("dispatcher") val dispatcher: Dispatcher = builder.dispatcher
//... 此处省略n个可配置的参数
constructor() : this(Builder())
init{
// 初始化其它的一些参数
// ...
// 校验参数合法性
verifyClientState()
}
class Builder constructor() {
internal var dispatcher: Dispatcher = Dispatcher()
//... 此处省略n个参数
// 巧用kotlin的apply实现参数赋值
fun dispatcher(dispatcher: Dispatcher) = apply {
this.dispatcher = dispatcher
}
// ...
// 构造返回OkHttpClient
fun build(): OkHttpClient = OkHttpClient(this)
}
}
至于OkHttpClient可以设置哪些参数,这里就不详细探究,本文只讲解OkHttpClient实现的大致流程。
RealCall
创建好OkHttpClient之后,还需要通过newCall方法创建一个RealCall对象
open class OkHttpClient internal constructor(
builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {
// ...
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
// ...
}
这里可以看到传入了一个Request对象,用于设置请求的地址,header等参数,Request类同样使用了建造者模式实现。
继续深入到RealCall类中去,通过开头的使用示例可以看到,同步请求使用的是RealCall的execute方法,异步请求使用的是enqueue方法,那么先从execute方法看起吧
class RealCall(
val client: OkHttpClient,
val originalRequest: Request,
val forWebSocket: Boolean
) : Call {
// 检查是否已经在执行网络请求,防止多线程情况下出现多次请求问题
private val executed = AtomicBoolean()
// ...
override fun execute(): Response {
check(executed.compareAndSet(false, true)) { "Already Executed" }
// 计时开始,用于统计请求超时
timeout.enter()
// 通知用户请求开始,会回调一个用户主动设置的listener
callStart()
try {
// 将请求添加到请求队列中
client.dispatcher.executed(this)
// 真正执行请求
return getResponseWithInterceptorChain()
} finally {
// 将本次call从请求队列中移除
client.dispatcher.finished(this)
}
}
}
再看异步请求是怎么做的
override fun enqueue(responseCallback: Callback) {
// 检查是否已经在请求
check(executed.compareAndSet(false, true)) { "Already Executed" }
callStart()
// 封装一个AsyncCall,丢入到请求队列中
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
可以看到不论是同步还是异步,都使用到了一个叫Dispatcher的东西,将请求丢进了请求队列中去,所以接下来看看Dispatcher做了哪些工作。
Dispatcher
OkHttp提供了一个默认的Dispatcher,用于管理每一个请求,当然用户也可以自定义一个。先看看添加同步请求怎么实现的
class Dispatcher constructor() {
// 同一时刻最大请求数
@get:Synchronized var maxRequests = 64
//...省略若干代码
// 同一时刻URL或IP最大请求数
@get:Synchronized var maxRequestsPerHost = 5
//...省略若干代码
// 异步等待队列
private val readyAsyncCalls = ArrayDeque<AsyncCall>()
// 异步执行队列
private val runningAsyncCalls = ArrayDeque<AsyncCall>()
// 同步执行队列
private val runningSyncCalls = ArrayDeque<RealCall>()
@get:Synchronized
// 异步请求线程池
@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!!
}
@Synchronized internal fun executed(call: RealCall) {
runningSyncCalls.add(call)
}
}
很简单,就是将Call丢进了runningSyncCalls队列中。可以看到Dispatcher中维护了三个队列和一个线程池,用于管理Call。
接下来看异步
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
// 添加进异步等待队列
readyAsyncCalls.add(call)
// 不是socket请求
if (!call.call.forWebSocket) {
// 找到同一host的请求,用于统计限制同一host请求数
val existingCall = findExistingCallWithHost(call.host)
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
}
}
promoteAndExecute()
}
再看promoteAndExecute方法
private fun promoteAndExecute(): Boolean {
this.assertThreadDoesntHoldLock()
val executableCalls = mutableListOf<AsyncCall>()
val isRunning: Boolean
synchronized(this) {
val i = readyAsyncCalls.iterator()
while (i.hasNext()) {
// 从等待队列中取一个Call
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()
// 将取到的Call丢进executableCalls中
executableCalls.add(asyncCall)
// 将从等待队列中取到的Call丢进runningAsyncCalls中
runningAsyncCalls.add(asyncCall)
}
// 正在执行的同步异步请求数是>0
isRunning = runningCallsCount() > 0
}
// 遍历执行Call
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
// 调用AsyncCall中的executeOn方法
asyncCall.executeOn(executorService)
}
return isRunning
}
Dispacher中还提供了一些请求结束,请求取消等等方法,这里就不再探究。
通过上面可以看到异步请求最终会封装成一个AsyncCall,并丢入到线程池中执行,那么AsyncCall一定是一个Runnable,所以接下来看下AsyncCall这个类
AsyncCall
AsyncCall是一个RealCall的内部类,这里主要看两个方法,executeOn和run方法
internal inner class AsyncCall(
private val responseCallback: Callback
) : Runnable {
fun executeOn(executorService: ExecutorService) {
// 判断当前线程没有持有锁
client.dispatcher.assertThreadDoesntHoldLock()
try {
// 通过线程池执行线程
executorService.execute(this)
} catch (e: RejectedExecutionException) {
// 省略n行代码
} finally {
if (!success) {
client.dispatcher.finished(this) // This call is no longer running!
}
}
}
override fun run() {
// 设置当前线程名称
threadName("OkHttp ${redactedUrl()}") {
// 计时开始
timeout.enter()
try {
// 执行真正的请求
val response = getResponseWithInterceptorChain()
// 回调结果
responseCallback.onResponse(this@RealCall, response)
} catch (e: IOException) {
// 请求失败
} catch (t: Throwable) {
cancel()
// 请求失败
} finally {
// 请求结束
client.dispatcher.finished(this)
}
}
}
}
这里就可以看到和同步请求一样,都是调用了RealCall的getResponseWithInterceptorChain方法请求数据,只是返回数据的方式不一样而已。所以接下来再看看getResponseWithInterceptorChain方法。
getResponseWithInterceptorChain
很明显这里可以看到,OkHttp执行网络请求使用到了责任链模式,
@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
val interceptors = mutableListOf<Interceptor>()
// 用户自定义的拦截器,可以有多个
interceptors += client.interceptors
// 重试和重定向拦截器
interceptors += RetryAndFollowUpInterceptor(client)
// 桥接拦截器,主要是设置一些通用的header
interceptors += BridgeInterceptor(client.cookieJar)
// 缓存拦截器
interceptors += CacheInterceptor(client.cache)
// 连接拦截器
interceptors += ConnectInterceptor
// 如果不是socket,再添加网络拦截器,可以有多个
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) {
//...
} finally {
//...
}
}
整个请求过程如图所示
通过上面可以看到,当我们发起一个请求时,最先调用的是用户自定义的拦截器(应用拦截器),而网络拦截器,是到执行请求之前才执行的。
本次分析到此为止,至于各个拦截器的内部实现原理是怎样的,后面有空了再看看。