OKhttp 源码解析(一)
这一期我们先从 Okhttp 发送求情 到 收到响应这个过程的主体框架进行的了解,后面几期在逐步深入源码细节。让我们一起来学习吧(~ _ ~)!
Okhttp 从4.0开始都逐步换成Kotlin ,所以我们看的源码也都用Kotlin吧)
友情提醒:大家阅读源码的时候,最好是从使用场景出发,从你熟悉的 API 进入源码,有目的性的去逐步了解内部实现原理。先扫清主线粗略的了解,在去深入细节(否则,会不断的进入新的细节就迷路了,别问我是怎么知道的 555~~)
示例代码
val client = OkHttpClient()
val url = "https://www.baidu.com/"
@Throws(IOException::class)
fun run(url: String): String? {
val request: Request = Request.Builder()
.url(url)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: java.io.IOException) {
}
override fun onResponse(call: Call, response: Response) {
println("Response status code :${response.code}")
Log.i("ResponseCode", response.code.toString())
}
})
return ""
}
最常用的就是 enqueue 方法. execute 用的比较少
进入 enqueue 发现它是 Call 接口种的 一个抽象方法
interface Call : Cloneable {
...
fun enqueue(responseCallback: Callback)
@Throws(IOException::class)
fun execute(): Response
...
那么往前找去看 newCall 这个方法,它的返回值Call 是 一个叫RealCall的构造方法
/** Prepares the [request] to be executed at some point in the future. */
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
进入RealCall 看 ,
有三个构造参数
val client: OkHttpClient 大管家的角色,各种通用配置,如控制链接超时时间 等
val originalRequest: Request, 里面包含了请求信息,get/post,请求header,body 等
val forWebSocket: Boolean WebSocket 全双工通信,服务端与各户端的长连接
class RealCall(
val client: OkHttpClient,
/** The application's original request unadulterated by redirects or auth headers. */
val originalRequest: Request,
val forWebSocket: Boolean
) : Call {
private val connectionPool: RealConnectionPool = client.connectionPool.delegate
private val eventListener: EventListener = client.eventListenerFactory.create(this)
private val timeout = object : AsyncTimeout() {
override fun timedOut() {
cancel()
}
}.apply {
timeout(client.callTimeoutMillis.toLong(), MILLISECONDS)
}
------
override fun enqueue(responseCallback: Callback) {
synchronized(this) {
check(!executed) { "Already Executed" }
executed = true
}
callStart() // 主要做请求的过程中的事件记录(分析问题用的)
client.dispatcher.enqueue(AsyncCall(responseCallback)) // 主要看这一句
}
接下来看 RelCall 的 enqueue 方法
client.dispatcher.enqueue(AsyncCall(responseCallback)) // 主要看这一句
调用了 client.dispatcher 的 enqueue
-
Dispatcher 线程调度 (同时有多个请求,通过它来完成)
-
内部使用Java 的 线程池来处理 ExecutorService (将请求切换到后台线程)
-
maxRequests (最大请求数64 ) maxRequestsPerHost(同一主机最大请求数5)
-
注意 maxRequests 和 maxRequestsPerHost 这俩个参数 都是可以被 set 的~~
-
-
dispatcher.enqueue (call: AsyncCall)
internal fun enqueue(call: AsyncCall) { synchronized(this) { 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) { // 用来记录 maxRequestsPerHost 数量的 val existingCall = findExistingCallWithHost(call.host) if (existingCall != null) call.reuseCallsPerHostFrom(existingCall) } } promoteAndExecute() }
-
将call 加入了一个 双向队列 readyAsyncCalls.add(call) (存放了准备要执行,还没执行的请求)
-
在看 promoteAndExecute() 方法
主要作用促进,将准备中的任务(readyAsyncCalls),放入执行任务队列(runningAsyncCalls),但 runningAsyncCalls 知识起一个标记作用,
最后要执行人任务的是 executableCalls ;
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)
}private fun promoteAndExecute(): Boolean { this.assertThreadDoesntHoldLock() val executableCalls = mutableListOf<AsyncCall>() val isRunning: Boolean synchronized(this) { val i = readyAsyncCalls.iterator() // 1 在这里遍历出来 while (i.hasNext()) { val asyncCall = i.next() //2 在这里筛选 可执行的 call if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity. if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity. i.remove() asyncCall.callsPerHost.incrementAndGet() //3 将可执行的 call 放入 executableCalls 和 runningAsyncCalls executableCalls.add(asyncCall) runningAsyncCalls.add(asyncCall) } isRunning = runningCallsCount() > 0 } //4 在遍历 executableCalls 挨个去执行 for (i in 0 until executableCalls.size) { val asyncCall = executableCalls[i] asyncCall.executeOn(executorService) } return isRunning }
-
-
重点来了 通过 asyncCall.executeOn(executorService) 挨个去执行
- 了解了 executeOn() 也就了解了整个执行过程对吧!
先来看 executorService 的这个入参 , 他是一个单一线程队列(马上就会执行)
if (executorServiceOrNull == null) {
executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
}
fun executeOn(executorService: ExecutorService) {
client.dispatcher.assertThreadDoesntHoldLock()
var success = false
try {
executorService.execute(this)
success = true
} catch (e: RejectedExecutionException) {
val ioException = InterruptedIOException("executor rejected")
ioException.initCause(e)
noMoreExchanges(ioException)
responseCallback.onFailure(this@RealCall, ioException)
} finally {
if (!success) {
client.dispatcher.finished(this) // This call is no longer running!
}
}
}
-
executorService.execute(this) 入参是 Runnble 但是传入一个 this ,说明当前类 AsyncCall 实现了Runnable 接口! 我们就直接去看它是怎样重写的 run() 方法好了
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) { // Do not signal the callback twice! 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) } } }
-
在run 方法中我们见到了 熟悉的 responseCallback.onResponse() 和 responseCallback. onFailure() 这两个回调方法,对应的就是第一段 示例代码中的 **onResponse()**和 onFailure() ,是不是感觉很亲切了呢!~
那么到这里整个 Okhttp的请求到响应的主体框架就闭环了,
与此同时,我们也发现 getResponseWithInterceptorChain() 返回了响应值,但是目前还没看到请求的执行的过程,那么也就说明 getResponseWithInterceptorChain() 包含了所有请求的具体过程,整个请求的核心方法 ,其内部使用 责任链模式 将整个工作的流程串了起来,这个我们后面再将!