本文基于OkHttp 4.3.1源碼分析
OkHttp - 官方地址
OkHttp - GitHub代碼地址
概括
本篇主要從OkHttp的兩個(gè)請(qǐng)求示例開(kāi)始率挣,對(duì)Okhttp的初始化工作刻伊,和請(qǐng)求從構(gòu)造、分發(fā)到執(zhí)行的流程進(jìn)行源碼分析介紹
OkHttp整體流程(本文覆蓋紅色部分)
本文覆蓋代碼流程圖
示例
使用OkHttp一般流程椒功,初始化一個(gè)共享OkHttpClient捶箱,構(gòu)建Request,然后OkHttpClient根據(jù)Request構(gòu)建Call动漾,接著執(zhí)行call讼呢,最后進(jìn)行Response處理
同步請(qǐng)求
public class GetExample {
OkHttpClient client = new OkHttpClient(); // 構(gòu)建共享的Client
String run(String url) throws IOException {
Request request = new Request.Builder() // 構(gòu)建request
.url(url)
.build();
// 構(gòu)建Call,執(zhí)行
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
public static void main(String[] args) throws IOException {
GetExample example = new GetExample();
String response = example.run("https://raw.github.com/square/okhttp/master/README.md");
System.out.println(response);
}
}
異步請(qǐng)求
public final class AsynchronousGet {
private final OkHttpClient client = new OkHttpClient();// 構(gòu)建共享Client
public void run() throws Exception {
// 構(gòu)建Request
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
// 構(gòu)建Call谦炬,執(zhí)行悦屏,回調(diào)接受處理
client.newCall(request).enqueue(new Callback() {
@Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(responseBody.string());
}
}
});
}
public static void main(String... args) throws Exception {
new AsynchronousGet().run();
}
}
源碼分析
構(gòu)建OkHttpClient
- OkHttpClient是Call的一個(gè)工廠類,OkHttpClient應(yīng)該是共享的键思,或者說(shuō)是單例
- 可以通過(guò)newBuilder來(lái)自定義Client
- 沒(méi)有必要關(guān)心 關(guān)閉和資源釋放
/*
* Factory for [calls][Call], which can be used to send HTTP requests and read their responses.
* ## OkHttpClients Should Be Shared
* ## Customize Your Client With newBuilder()
* ## Shutdown Isn't Necessary
* /
open class OkHttpClient internal constructor(
builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {
// 3. 成員變量初始化
...
// 1. 內(nèi)部無(wú)參數(shù)構(gòu)造函數(shù)
constructor() : this(Builder())
// 4. OkHttpClient函數(shù)初始化
init {
// 初始化證書(shū)和攔截器等判斷邏輯
...
}
// 2. Builder構(gòu)造函數(shù)
class Builder constructor() {
...
}
}
OkHttpClient.Builder
Builder模式础爬,提供自定義配置化能力,同時(shí)有一份無(wú)需關(guān)心的默認(rèn)配置
class Builder constructor() {
internal var dispatcher: Dispatcher = Dispatcher()
internal var connectionPool: ConnectionPool = ConnectionPool()
internal val interceptors: MutableList<Interceptor> = mutableListOf()
internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
internal var retryOnConnectionFailure = true
internal var authenticator: Authenticator = Authenticator.NONE
internal var followRedirects = true
internal var followSslRedirects = true
internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
internal var cache: Cache? = null
internal var dns: Dns = Dns.SYSTEM
internal var proxy: Proxy? = null
internal var proxySelector: ProxySelector? = null
internal var proxyAuthenticator: Authenticator = Authenticator.NONE
internal var socketFactory: SocketFactory = SocketFactory.getDefault()
internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
internal var x509TrustManagerOrNull: X509TrustManager? = null
internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS
internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
internal var certificateChainCleaner: CertificateChainCleaner? = null
internal var callTimeout = 0
internal var connectTimeout = 10_000
internal var readTimeout = 10_000
internal var writeTimeout = 10_000
internal var pingInterval = 0
}
OkHttpClient成員變量初始化
- 初始化成員變量
- JvmName是為了支持兼容3.x
@get:JvmName("dispatcher") val dispatcher: Dispatcher = builder.dispatcher
@get:JvmName("connectionPool") val connectionPool: ConnectionPool = builder.connectionPool
@get:JvmName("interceptors") val interceptors: List<Interceptor> =
builder.interceptors.toImmutableList()
@get:JvmName("networkInterceptors") val networkInterceptors: List<Interceptor> =
builder.networkInterceptors.toImmutableList()
@get:JvmName("eventListenerFactory") val eventListenerFactory: EventListener.Factory =
builder.eventListenerFactory
@get:JvmName("retryOnConnectionFailure") val retryOnConnectionFailure: Boolean =
builder.retryOnConnectionFailure
@get:JvmName("cookieJar") val cookieJar: CookieJar = builder.cookieJar
@get:JvmName("cache") val cache: Cache? = builder.cache
....
構(gòu)建Request
Request 對(duì)應(yīng)HTTP請(qǐng)求中的Request吼鳞,OkHttp依舊是Builder構(gòu)建模式構(gòu)建Request
Request.Builder
支持url看蚜、method、headers赔桌、body的配置
open class Builder {
internal var url: HttpUrl? = null
internal var method: String
internal var headers: Headers.Builder
internal var body: RequestBody? = null
// 構(gòu)造Request
open fun build(): Request {
return Request(
checkNotNull(url) { "url == null" },
method,
headers.build(),
body,
tags.toImmutableMap()
)
}
}
Request
通過(guò)Request.Builder構(gòu)造Request實(shí)例
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>
) {
...
}
構(gòu)建Call
OkHttpClient.newCall
OkHttpClient 實(shí)現(xiàn)了Call.Factory供炎,作為Call的構(gòu)造工廠類
override fun newCall(request: Request): Call {
// 執(zhí)行 RealCall的構(gòu)造call方法
return RealCall.newRealCall(this, request, forWebSocket = false)
}
RealCall.newRealCall
構(gòu)造Call真正方法,另外創(chuàng)建了一個(gè) 發(fā)射器疾党,接下來(lái)先了解下Call
companion object {
fun newRealCall(
client: OkHttpClient,
originalRequest: Request,
forWebSocket: Boolean
): RealCall {
return RealCall(client, originalRequest, forWebSocket).apply {
// 構(gòu)造了一個(gè) 發(fā)射器音诫,它是應(yīng)用層和網(wǎng)絡(luò)層交互的橋梁,后面會(huì)著重介紹
transmitter = Transmitter(client, this)
}
}
}
RealCall
Call定義為一個(gè)準(zhǔn)備好執(zhí)行的請(qǐng)求雪位,它是能被取消的竭钝,且它只能被執(zhí)行一次(http請(qǐng)求也是一次執(zhí)行)
包括一個(gè)核心成員變量 Transmitter ,兩個(gè)重要方法 execute(同步) 和 enqueue(異步)
internal class RealCall private constructor(
val client: OkHttpClient,
/** The application's original request unadulterated by redirects or auth headers. */
val originalRequest: Request,
val forWebSocket: Boolean
) : Call {
// 發(fā)射機(jī)
private lateinit var transmitter: Transmitter
// 同步請(qǐng)求執(zhí)行方法
override fun execute(): Response {
...
}
// 異步請(qǐng)求執(zhí)行方法
override fun enqueue(responseCallback: Callback) {
...
}}
// 取消請(qǐng)求
override fun cancel() {
transmitter.cancel()
}
同步請(qǐng)求
RealCall.execute
- 請(qǐng)求前校驗(yàn)邏輯雹洗,僅能執(zhí)行一次香罐,和過(guò)期時(shí)間邏輯判斷邏輯
- 通知請(qǐng)求start事件,便于metrics 指標(biāo)數(shù)據(jù)收集
- 將call加入分發(fā)器的同步請(qǐng)求隊(duì)列中
- 通過(guò)攔截器責(zé)任鏈模式進(jìn)行請(qǐng)求和返回一系列邏輯處理
override fun execute(): Response {
// 檢查是否已經(jīng)執(zhí)行
synchronized(this) {
check(!executed) { "Already Executed" }
executed = true
}
// 過(guò)期時(shí)間邏輯时肿,如果配置了會(huì)有WatchDog線程進(jìn)行Watch然后執(zhí)行退出邏輯
transmitter.timeoutEnter()
// 通知start庇茫,最后會(huì)通過(guò) EventListener 發(fā)出時(shí)間,主要目的是收集 metrics events
transmitter.callStart()
try {
// 調(diào)用client的dispatcher分發(fā)器執(zhí)行call(將call加入同步call隊(duì)列)
client.dispatcher.executed(this)
// 通過(guò)攔截器責(zé)任鏈模式進(jìn)行請(qǐng)求和返回處理等一系類邏輯
return getResponseWithInterceptorChain()
} finally {
client.dispatcher.finished(this)
}
}
RealCall.getResponseWithInterceptorChain
- 配置攔截器螃成,所有請(qǐng)求和響應(yīng)處理邏輯解耦到各個(gè)攔截器負(fù)責(zé)模塊
- 構(gòu)造攔截器鏈?zhǔn)秸{(diào)用處理類RealInterceptorChain實(shí)例
- chain.proceed 進(jìn)行攔截器的鏈?zhǔn)秸{(diào)用
fun getResponseWithInterceptorChain(): Response {
// 構(gòu)建所有的攔截器
val interceptors = mutableListOf<Interceptor>()
interceptors += client.interceptors // client配置的攔截器
interceptors += RetryAndFollowUpInterceptor(client) // 重試機(jī)制攔截器
interceptors += BridgeInterceptor(client.cookieJar) // 請(qǐng)求和返回橋(http信息配置和解析)攔截器
interceptors += CacheInterceptor(client.cache) // 緩存攔截
interceptors += ConnectInterceptor // 連接攔截器
if (!forWebSocket) {
interceptors += client.networkInterceptors
}
interceptors += CallServerInterceptor(forWebSocket) // 執(zhí)行攔截器
// 攔截器核心處理類
val chain = RealInterceptorChain(interceptors, transmitter, null, 0, originalRequest, this,
client.connectTimeoutMillis, client.readTimeoutMillis, client.writeTimeoutMillis)
var calledNoMoreExchanges = false
try {
// 鏈?zhǔn)秸{(diào)用
val response = chain.proceed(originalRequest)
if (transmitter.isCanceled) { // 處理取消
response.closeQuietly()
throw IOException("Canceled")
}
return response //返回請(qǐng)求結(jié)果
} catch (e: IOException) {
calledNoMoreExchanges = true
throw transmitter.noMoreExchanges(e) as Throwable
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null)
}
}
}
異步請(qǐng)求
RealCall.enqueue
- 構(gòu)造一個(gè)異步call
- 調(diào)用dispatcher 入隊(duì)AsyncCall
override fun enqueue(responseCallback: Callback) {
synchronized(this) {
check(!executed) { "Already Executed" }
executed = true
}
transmitter.callStart()
// 構(gòu)造 AsyncCall 旦签,接著分發(fā)器入隊(duì)操作
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
Dispatcher 分發(fā)器隊(duì)Call進(jìn)行分發(fā)執(zhí)行
- 初始化時(shí)啥容,構(gòu)造分發(fā)器的線程池,及對(duì)應(yīng)執(zhí)行參數(shù)
- 主要管理異步請(qǐng)求的處理(異步Call入隊(duì)顷霹、并發(fā)執(zhí)行)
class Dispatcher constructor() {
// 默認(rèn)最大請(qǐng)求數(shù) 64
@get:Synchronized var maxRequests = 64
// 默認(rèn)最大并發(fā)Host 5
@get:Synchronized var maxRequestsPerHost = 5
// 線程池執(zhí)行器 默認(rèn)創(chuàng)建可緩存線程池
@get:JvmName("executorService") val executorService: ExecutorService
get() {
if (executorServiceOrNull == null) {
executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
SynchronousQueue(), threadFactory("OkHttp Dispatcher", false))
}
return executorServiceOrNull!!
}
/** 準(zhǔn)備好的異步Call對(duì)列 */
private val readyAsyncCalls = ArrayDeque<AsyncCall>()
/** 執(zhí)行中異步call對(duì)列 */
private val runningAsyncCalls = ArrayDeque<AsyncCall>()
/** 同步call對(duì)列 */
private val runningSyncCalls = ArrayDeque<RealCall>()
// 異步Call 入隊(duì)操作
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
readyAsyncCalls.add(call)
// same host情況下的復(fù)用邏輯處理
if (!call.get().forWebSocket) {
val existingCall = findExistingCallWithHost(call.host())
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
}
}
promoteAndExecute() // 準(zhǔn)備線程池執(zhí)行器咪惠,及執(zhí)行
}
// 執(zhí)行Call
private fun promoteAndExecute(): Boolean {
this.assertThreadDoesntHoldLock()
val executableCalls = mutableListOf<AsyncCall>()
val isRunning: Boolean
synchronized(this) {
// 遍歷所有的ready 異步 call
val i = readyAsyncCalls.iterator()
while (i.hasNext()) {
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()
executableCalls.add(asyncCall) // 加入此次執(zhí)行隊(duì)列緩存
runningAsyncCalls.add(asyncCall) // 加入正在執(zhí)行隊(duì)列
}
isRunning = runningCallsCount() > 0
}
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService) // 將線程執(zhí)行器傳入call,在Call中進(jìn)行執(zhí)行
}
return isRunning
}
/** 同步call淋淀,添加到隊(duì)列 */
@Synchronized internal fun executed(call: RealCall) {
runningSyncCalls.add(call)
}
}
AsyncCall執(zhí)行
- executeOn 遥昧,線程池執(zhí)行器執(zhí)行Runnable
- run,通過(guò)攔截器進(jìn)行請(qǐng)求和獲取響應(yīng)結(jié)果
fun executeOn(executorService: ExecutorService) {
client.dispatcher.assertThreadDoesntHoldLock()
var success = false
try {
// 線程池 執(zhí)行器執(zhí)行
executorService.execute(this)
success = true
}
}
// 執(zhí)行方法
override fun run() {
threadName("OkHttp ${redactedUrl()}") {
var signalledCallback = false
transmitter.timeoutEnter()
try {
// 同“同步請(qǐng)求” 最終執(zhí)行攔截器鏈?zhǔn)秸{(diào)用
val response = getResponseWithInterceptorChain()
signalledCallback = true
// 響應(yīng) 回調(diào)
responseCallback.onResponse(this@RealCall, response)
} catch (e: IOException) {
...
} finally {
client.dispatcher.finished(this)
}
}
}