OkHttp4.x源碼解析(一)--基本流程

從事Android開發(fā)多年,做過的項目中http請求框架一直用的OkHttp,從鴻神的okhttputils,到后來的Retrofit,萬變不離其宗

應(yīng)該有很多同學(xué)和我一樣也都在這使用這些框架,但也只僅僅停留在會用的狀態(tài),知道它牛批,用的人最多,但是具體牛批在哪,也說不出個所以然

但是現(xiàn)在都0202了

本著對自己負(fù)責(zé)的心態(tài)和讓自己在公司瘋狂裁員的處境下能夠更加淡然面對(能給我安全感的不只有手機和錢包,還有技術(shù)的提高)

于是我默默的打開了https://github.com/square/okhttp

然后就是一連串的懵逼和對自己對OkHttp了解程度的打臉(我以為我用的3.10已經(jīng)很新了)

??什么時間可更新到4.3.1版本了?
??又是什么時間從Java遷移到Kotlin了?
??api變化大嗎?
...

查閱到官方手冊

OkHttp 4.x upgrades our implementation language from Java to Kotlin and keeps everything else the same. We’ve chosen Kotlin because it gives us powerful new capabilities while integrating closely with Java.
We spent a lot of time and energy on retaining strict compatibility with OkHttp 3.x. We’re even keeping the package name the same: okhttp3!

概括就是從4.x開始遷移到了Kotlin,并保持與okhttp3.x的嚴(yán)格兼容性,連包名都沒變還是okhttp3

看來Kotlin真的是大勢所趨啊,幸好在一年多以前已經(jīng)可以使用kotlin開發(fā)了

不廢話了,下面介紹OkHttp的基本請求和相應(yīng)流程,源碼就基于目前的最新版4.3.1

1.OkHttp最簡單的用法

請求方式分為同步請求和異步請求

val okHttpClient = OkHttpClient.Builder().build()
val request = Request.Builder().url("https://xxxx").build()
//1.同步請求直接返回response
val response = okHttpClient.newCall(request).execute()
//2.異步請求
okHttpClient.newCall(request).enqueue(object : Callback {
    override fun onFailure(call: Call, e: IOException) {
        //網(wǎng)絡(luò)請求失敗的回調(diào)
    }

    override fun onResponse(call: Call, response: Response) {
        //網(wǎng)絡(luò)請求成功的回調(diào)
    }
})

2.流程解析

2.1 創(chuàng)建OkHttpClient

OkHttpClient是通信的客戶端實例,用來統(tǒng)一調(diào)度發(fā)起請求與解析響應(yīng)

val okHttpClient = OkHttpClient.Builder()
    .connectTimeout()
    .addInterceptor()
    .build()

OkHttpClient使用建造者模式為其設(shè)置一些參數(shù),例如超時時間和自定義的攔截器等。一般我們在項目中OkHttpClient都是單例的,因為每個OkHttpClient實例都擁有自己的連接池、線程池和調(diào)度器,會對網(wǎng)絡(luò)請求進行統(tǒng)一管理和連接復(fù)用,減少資源浪費和網(wǎng)絡(luò)延遲

class OkHttpClient {
    ...
    //調(diào)度器,內(nèi)部有線程池
    val dispatcher: Dispatcher = builder.dispatcher
    //連接池
    val connectionPool: ConnectionPool = builder.connectionPool
    ...
}

2.2 創(chuàng)建Request

Request封裝了請求的具體信息,例如請求的url、請求方式、請求頭、請求體

class Request internal constructor(
  @get:JvmName("url") val url: HttpUrl,
  @get:JvmName("method") val method: String,
  @get:JvmName("headers") val headers: Headers,
  @get:JvmName("body") val body: RequestBody?,
  internal val tags: Map<Class<*>, Any>
)

也是通過建造者模式設(shè)置這些參數(shù)

val request = Request.Builder()
    .url()
    .post()
    .header()
    .build()

2.3 創(chuàng)建Call

Call是一個接口,具體的實現(xiàn)類是RealCall,OkHttp的請求也都封裝了RealCall中

class OkHttpClient {
    ...
    override fun newCall(request: Request): Call {
        return RealCall.newRealCall(this, request, false)
    }
    ...
}

interface Call : Cloneable {

    //請求的信息
    fun request(): Request
    //同步請求,會阻塞線程知道返回結(jié)果Response
    fun execute(): Response
    //異步請求,通過回調(diào)得到Response
    fun enqueue(responseCallback: Callback)
    //取消請求
    fun cancel()
    //請求是否在執(zhí)行
    fun isExecuted(): Boolean
    //請求是否被取消
    fun isCanceled(): Boolean

    fun timeout(): Timeout

    public override fun clone(): okhttp3.Call

    interface Factory {
        fun newCall(request: Request): okhttp3.Call
    }
}

調(diào)用OkHttpClient的newCall()方法創(chuàng)建RealCall對象,這時會傳入當(dāng)前OkHttpClient實例this和上一步創(chuàng)建的request

2.4 開始請求

2.4.1 調(diào)度器Dispatcher

Dispatcher是OkHttp的一個核心類,負(fù)責(zé)調(diào)度同步和異步請求,取消請求,管理每一個請求的狀態(tài),內(nèi)部維護了一個用來執(zhí)行異步任務(wù)的線程池和三個請求隊列,所有的請求Call都要先添加到請求隊列

class Dispatcher {
    ...
    //最大任務(wù)數(shù)
    var maxRequests = 64
    //同一主機下最大任務(wù)數(shù)
    var maxRequestsPerHost = 5
    //準(zhǔn)備運行的異步請求
    private val readyAsyncCalls = ArrayDeque<RealCall.AsyncCall>()
    //正在運行的異步請求
    private val runningAsyncCalls = ArrayDeque<RealCall.AsyncCall>()
    //正在運行的同步請求
    private val runningSyncCalls = ArrayDeque<RealCall>()
    //執(zhí)行異步請求的線程池
    private var executorServiceOrNull: ExecutorService? = null
    val executorService: ExecutorService
        get() {
            if (executorServiceOrNull == null) {
                executorServiceOrNull = ThreadPoolExecutor(
                    0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
                    SynchronousQueue(), threadFactory("OkHttp Dispatcher", false)
                )
            }
            return executorServiceOrNull!!
        }
    ...
}
2.4.2 同步請求

同步請求會調(diào)用RealCall的execute方法,將自己添加進dispatcher的正在執(zhí)行的任務(wù)隊列,然后調(diào)用getResponseWithInterceptorChain方法得到response,最后又會調(diào)用dispatcher的finished方法從隊列移除

class Dispatcher {
    ...
    override fun execute(): Response {
        synchronized(this) {
            //檢測是否重復(fù)調(diào)用
            check(!executed) { "Already Executed" }
            executed = true
        }
        transmitter.timeoutEnter()
        transmitter.callStart()
        try {
            //dispatcher的executed方法,將任務(wù)添加進正在運行的同步請求隊列
            client.dispatcher.executed(this)
            //調(diào)用getResponseWithInterceptorChain方法
            return getResponseWithInterceptorChain()
        } finally {
            //將任務(wù)從隊列移除
            client.dispatcher.finished(this)
        }
    }
    ...
}
2.4.3 異步請求

異步請求會調(diào)用RealCall的enqueue方法,傳入一個Callback用于回調(diào)網(wǎng)絡(luò)請求結(jié)果

override fun enqueue(responseCallback: Callback) {
    synchronized(this) {
        //檢測是否重復(fù)調(diào)用
        check(!executed) { "Already Executed" }
        executed = true
    }
    transmitter.callStart()
    //dispatcher的enqueue方法
    client.dispatcher.enqueue(AsyncCall(responseCallback))
}

RealCall的enqueue方法里面進而又調(diào)用okHttpClient的成員dispatcher的enqueue方法,這時候?qū)allback進行的包裝,傳建一個AsyncCall

class Dispatcher {
    ...
    internal fun enqueue(call: RealCall.AsyncCall) {
        ...
        synchronized(this) {
            //添加進準(zhǔn)備隊列
            readyAsyncCalls.add(call)
        }
        //取出可執(zhí)行的任務(wù)
        promoteAndExecute()
    }

    private fun promoteAndExecute(): Boolean {
        ...
        //可執(zhí)行任務(wù)的集合
        val executableCalls = mutableListOf<RealCall.AsyncCall>()
        val isRunning: Boolean
        synchronized(this) {
            val i = readyAsyncCalls.iterator()
            while (i.hasNext()) {
                val asyncCall = i.next()

                //判斷是否超過最大任務(wù)數(shù)
                if (runningAsyncCalls.size >= this.maxRequests) break
                //判斷是否超過同一主機下最大任務(wù)數(shù)
                if (asyncCall.callsPerHost().get() >= this.maxRequestsPerHost) continue
                //從等待隊列移除
                i.remove()
                asyncCall.callsPerHost().incrementAndGet()
                //添加到可執(zhí)行任務(wù)的集合
                executableCalls.add(asyncCall)
                //添加到正在運行的隊列
                runningAsyncCalls.add(asyncCall)
            }
            isRunning = runningCallsCount() > 0
        }

        for (i in 0 until executableCalls.size) {
            val asyncCall = executableCalls[i]
            //執(zhí)行任務(wù),調(diào)用asyncCall的executeOn方法
            asyncCall.executeOn(executorService)
        }

        return isRunning
    }
    ...
}

而AsyncCall又是一個Runnable,會在executeOn中將自己添加到線程池executorService ,在run方法中得到網(wǎng)絡(luò)請求的結(jié)果response

internal inner class AsyncCall(
    private val responseCallback: Callback
) : Runnable {
    ...
    //開啟任務(wù),執(zhí)行run方法,此處省略了很多代碼
    fun executeOn(executorService: ExecutorService) {
        var success = false
        try {
            ...
            //開啟異步任務(wù)
            executorService.execute(this)
            success = true
        } catch (e: RejectedExecutionException) {
            ...
            //失敗回調(diào)
            responseCallback.onFailure(this@RealCall, ioException)
        } finally {
            ...
            if (!success) {
                //如果開啟任務(wù)失敗將任務(wù)從隊列移除
                client.dispatcher.finished(this)
            }
        }
    }

    override fun run() {
        try {
            ...
            //調(diào)用這個方法得到結(jié)果response,進行回調(diào)
            val response = getResponseWithInterceptorChain()
            responseCallback.onResponse(this@RealCall, response)
        } catch (e: IOException) {
            ...
            //異常也要回調(diào)
            responseCallback.onFailure(this@RealCall, e)
        } catch (t: Throwable) {
            ...
            //異常也要回調(diào)
            responseCallback.onFailure(this@RealCall, canceledException)
        } finally {
            ...
            //不管成功還是失敗都要將任務(wù)從隊列移除
            client.dispatcher.finished(this)
        }
    }
    ...
}

當(dāng)調(diào)用dispatcher的finished方法時會將當(dāng)前任務(wù)從隊列中移除,同時會檢查是否還有等待的異步任務(wù)

class Dispatcher {
    ...
    internal fun finished(call: RealCall.AsyncCall) {
        call.callsPerHost().decrementAndGet()
        finished(runningAsyncCalls, call)
    }

    private fun <T> finished(calls: Deque<T>, call: T) {
        ...
        //繼續(xù)調(diào)用promoteAndExecute方法
        val isRunning = promoteAndExecute()
    }
    ...
}

相同點:同步請求和異步請求最終都會調(diào)用getResponseWithInterceptorChain方法得到response

class RealCall {
    ...
    fun getResponseWithInterceptorChain(): Response {
        // 創(chuàng)建攔截器棧
        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(interceptors, transmitter, null, 0, originalRequest, this,
            client.connectTimeoutMillis, client.readTimeoutMillis, client.writeTimeoutMillis)

        var calledNoMoreExchanges = false
        try {
            val response = chain.proceed(originalRequest)
            if (transmitter.isCanceled) {
                response.closeQuietly()
                throw IOException("Canceled")
            }
            //返回結(jié)果
            return response
        } catch (e: IOException) {
            calledNoMoreExchanges = true
            throw transmitter.noMoreExchanges(e) as Throwable
        } finally {
            if (!calledNoMoreExchanges) {
                transmitter.noMoreExchanges(null)
            }
        }
    }
    ...
}

到此整個請求就完成了,拿到結(jié)果Response,同步請求直接返回,異步請求用Callback進行回調(diào)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容