文章目录
整体框架 :什么,还有这么简单的OkHttp源码分析?
Dispatcher过程 :三方库源码笔记-OkHttp 源码详解
OPPO互联网技术 :OkHttp源码深度解析
一.OkHttp的源码框架
1.从一个例子开始
val okHttClient = OkHttpClient.Builder()
.connectTimeout(Duration.ofSeconds(10))
.readTimeout(Duration.ofSeconds(10))
.writeTimeout(Duration.ofSeconds(10))
.retryOnConnectionFailure(true)
.build()
val request = Request.Builder().url(URL).build()
val call = okHttClient.newCall(request)
val response = call.execute()
OkHttp在请求网络的时候,首先是要创建okHttpClient对象,OkHttpClient 包含了对网络请求的全局配置信息,包括链接超时时间、读写超时时间、链接失败重试等各种配置。然后由okHttpClient执行一个 newCall 方法,将用户编写的request传入,然后就可以执行excuted或者enqueue方法进行网络请求。
2.Call
当调用 okHttClient.newCall(request)时就会得到一个 Call 对象
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
它返回的是一个Call类型的接口,实际的实现是 RealCall ,也就是说我们发起的同步异步请求实际上都是靠方法来实现的。它的主要逻辑为:
- 判读是否重复请求
- 事件记录
- 将自身加入到 dispatcher 中,并在请求结束时从 dispatcher 中移除自身
- 通过 getResponseWithInterceptorChain 方法得到 Response 对象
override fun execute(): Response {
//1.检查是否是同一个请求的再次执行
check(executed.compareAndSet(false, true)) {
"Already Executed" }
timeout.enter()
//2.事件记录,这是OkHttp内部的事件监听
callStart()
try {
//3.调用dispatcher
client.dispatcher.executed(this)
//4.通过 getResponseWithInterceptorChain 方法得到 Response 对象
return getResponseWithInterceptorChain()
} finally {
client.dispatcher.finished(this)
}
}
override fun enqueue(responseCallback: Callback) {
//1.
check(executed.compareAndSet(false, true)) {
"Already Executed" }
//2.
callStart()
//3.
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
注意,这里的异步请求发给dispatcher的是一个AsyncCall对象,他是RealCall的一个内部类,继承了Runable接口。
3.dispatcher
Dispatcher 是一个调度器,用于对全局的网络请求进行缓存调度,RealCall 的同步或者异步请求方法最后又都要进入到 dispatcher调度器中进行调度。其包含以下几个成员变量
class Dispatcher constructor() {
//最大请求数
var maxRequests = 64
//指向同一Host的最大请求数
var maxRequestsPerHost = 5
//线程池
private var executorServiceOrNull: ExecutorService? = null
val executorService: ExecutorService
get() {
if (executorServiceOrNull == null) {
executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
}
return executorServiceOrNull!!
}
// 三个双向队列
private val readyAsyncCalls = ArrayDeque<AsyncCall>()
private val runningAsyncCalls = ArrayDeque<AsyncCall>()
private val runningSyncCalls = ArrayDeque<RealCall>()
3.1 同步请求:
如果是同步请求,在请求开始前,调度器会把它添加到 同步队列 中,然后调用 getResponseWithInterceptorChain()方法进行真正的网络请求。最后在从同步队列中移除。
// Dispatcher/executed
@Synchronized internal fun executed(call: RealCall) {
runningSyncCalls.add(call)
}
3.2 异步请求:
如果是异步请求,调度器会先把它放在 异步就绪队列 中,该请求是否可以发起受masRequests(请求总数)和maxRequestsPerHost(指向同个主机的请求总数)影响。如果符合条件,那么就会从 异步就绪队列 取出请求加入到 异步运行队列。最后遍历队列,调用每一个对象的executeOn方法。
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
//加入异步就绪队列
readyAsyncCalls.add(call)
promoteAndExecute()
}
// promoteAndExecute()
private fun promoteAndExecute(): Boolean {
synchronized(this) {
val i = readyAsyncCalls.iterator()
//遍历异步就绪队列
while (i.hasNext()) {
val asyncCall = i.next()
//如果异步运行队列中的请求数大于最大请求个数,直接返回
if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
//如果指向同一个主机的请求数大于5,先跳过改请求,继续判断下一个。
if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
//如果上面的判断都没问题了,把它加入到异步运行队列中
i.remove()
asyncCall.callsPerHost.incrementAndGet()
//这里的这个可执行队列其实就是异步运行队列的一个拷贝
executableCalls.add(asyncCall)
runningAsyncCalls.add(asyncCall)
}
isRunning = runningCallsCount() > 0
}
//遍历可执行队列,拿到每一个AsyncCall对象,调用它的executeOn方法。
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)
}
return isRunning
}
然后会在executeOn中用传入的线程池执行异步请求。
//AsyncCall/executeOn