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

從事Android開(kāi)發(fā)多年,做過(guò)的項(xiàng)目中http請(qǐng)求框架一直用的OkHttp,從鴻神的okhttputils,到后來(lái)的Retrofit,萬(wàn)變不離其宗

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

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

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

于是我默默的打開(kāi)了https://github.com/square/okhttp

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

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

查閱到官方手冊(cè)

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開(kāi)始遷移到了Kotlin,并保持與okhttp3.x的嚴(yán)格兼容性,連包名都沒(méi)變還是okhttp3

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

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

1.OkHttp最簡(jiǎn)單的用法

請(qǐng)求方式分為同步請(qǐng)求和異步請(qǐng)求

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

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

2.流程解析

2.1 創(chuàng)建OkHttpClient

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

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

OkHttpClient使用建造者模式為其設(shè)置一些參數(shù),例如超時(shí)時(shí)間和自定義的攔截器等。一般我們?cè)陧?xiàng)目中OkHttpClient都是單例的,因?yàn)槊總€(gè)OkHttpClient實(shí)例都擁有自己的連接池、線程池和調(diào)度器,會(huì)對(duì)網(wǎng)絡(luò)請(qǐng)求進(jìn)行統(tǒng)一管理和連接復(fù)用,減少資源浪費(fèi)和網(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封裝了請(qǐng)求的具體信息,例如請(qǐng)求的url、請(qǐng)求方式、請(qǐng)求頭、請(qǐng)求體

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>
)

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

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

2.3 創(chuàng)建Call

Call是一個(gè)接口,具體的實(shí)現(xiàn)類(lèi)是RealCall,OkHttp的請(qǐng)求也都封裝了RealCall中

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

interface Call : Cloneable {

    //請(qǐng)求的信息
    fun request(): Request
    //同步請(qǐng)求,會(huì)阻塞線程知道返回結(jié)果Response
    fun execute(): Response
    //異步請(qǐng)求,通過(guò)回調(diào)得到Response
    fun enqueue(responseCallback: Callback)
    //取消請(qǐng)求
    fun cancel()
    //請(qǐng)求是否在執(zhí)行
    fun isExecuted(): Boolean
    //請(qǐng)求是否被取消
    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對(duì)象,這時(shí)會(huì)傳入當(dāng)前OkHttpClient實(shí)例this和上一步創(chuàng)建的request

2.4 開(kāi)始請(qǐng)求

2.4.1 調(diào)度器Dispatcher

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

class Dispatcher {
    ...
    //最大任務(wù)數(shù)
    var maxRequests = 64
    //同一主機(jī)下最大任務(wù)數(shù)
    var maxRequestsPerHost = 5
    //準(zhǔn)備運(yùn)行的異步請(qǐng)求
    private val readyAsyncCalls = ArrayDeque<RealCall.AsyncCall>()
    //正在運(yùn)行的異步請(qǐng)求
    private val runningAsyncCalls = ArrayDeque<RealCall.AsyncCall>()
    //正在運(yùn)行的同步請(qǐng)求
    private val runningSyncCalls = ArrayDeque<RealCall>()
    //執(zhí)行異步請(qǐng)求的線程池
    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 同步請(qǐng)求

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

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

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

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

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

class Dispatcher {
    ...
    internal fun enqueue(call: RealCall.AsyncCall) {
        ...
        synchronized(this) {
            //添加進(jìn)準(zhǔn)備隊(duì)列
            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()

                //判斷是否超過(guò)最大任務(wù)數(shù)
                if (runningAsyncCalls.size >= this.maxRequests) break
                //判斷是否超過(guò)同一主機(jī)下最大任務(wù)數(shù)
                if (asyncCall.callsPerHost().get() >= this.maxRequestsPerHost) continue
                //從等待隊(duì)列移除
                i.remove()
                asyncCall.callsPerHost().incrementAndGet()
                //添加到可執(zhí)行任務(wù)的集合
                executableCalls.add(asyncCall)
                //添加到正在運(yùn)行的隊(duì)列
                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又是一個(gè)Runnable,會(huì)在executeOn中將自己添加到線程池executorService ,在run方法中得到網(wǎng)絡(luò)請(qǐng)求的結(jié)果response

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

    override fun run() {
        try {
            ...
            //調(diào)用這個(gè)方法得到結(jié)果response,進(jìn)行回調(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ù)從隊(duì)列移除
            client.dispatcher.finished(this)
        }
    }
    ...
}

當(dāng)調(diào)用dispatcher的finished方法時(shí)會(huì)將當(dāng)前任務(wù)從隊(duì)列中移除,同時(shí)會(huì)檢查是否還有等待的異步任務(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ǎn):同步請(qǐng)求和異步請(qǐng)求最終都會(huì)調(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)
            }
        }
    }
    ...
}

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

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

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