OkHttp目前是Android平台主流的网络请求框架,包括最近比较出名的Retrofit网络请求库也是基于OkHttp框架来实现的,我们有必要学习下它的实现原理.
我们一般用OkHttp的使用方法如下:
private val client = OkHttpClient.Builder().build()
val request = Request.Builder()
.url(server.url("/"))
.header("Accept", "text/plain")
.build()
//同步请求
val response = client.newCall(request).execute()
//异步请求
val response = client.newCall(request).enqueue(object :Callback{
override fun onFailure(call: Call, e: IOException) {
TODO("Not yet implemented")
}
override fun onResponse(call: Call, response: Response) {
TODO("Not yet implemented")
}
})
我们今天就通过这个流程来分析OkHttp底层是怎么实现的.
以下是OkHttp流程图:
我们先从OkHttp构造方法开始分析
OkHttp有个内部类Builder,采用了Builder设计模式
fun build(): OkHttpClient = OkHttpClient(this)
通过进入OkHttpClient构造方法我们知道里面设置了很多初始值:
@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()//第三方APP拦截器
@get:JvmName("networkInterceptors") val networkInterceptors: List<Interceptor> =
builder.networkInterceptors.toImmutableList()//网络拦截器
@get:JvmName("eventListenerFactory") val eventListenerFactory: EventListener.Factory =
builder.eventListenerFactory//事件监听回调
等等
接着我们进入OkHttpClient的newCall方法
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
调用newCall方法返回RealCall对象,如下是RealCall的构造方法
```kotlin
class RealCall(
val client: OkHttpClient,
/** The application's original request unadulterated by redirects or auth headers. */
val originalRequest: Request,
val forWebSocket: Boolean
) : Call {
我们看到构造方法中只是做了一些数据传递。并且RealCall实现了Call接口.
由于网络请求同步执行和异步执行内部实现原理类似,这里我们只分析异步请求实现
override fun enqueue(responseCallback: Callback) {
synchronized(this) {
//只允许调用一次
check(!executed) { "Already Executed" }
executed = true
}
callStart()
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
我们看到在这里限制了同一个网络请求只能执行一次.
callStart()这里执行了回调,通知注册者请求开始.
//向队列中添加异步任务,如果是非网页行的任务,并且异步队列或者
// 正在运行的异步任务队列中存在相同host的
//任务,就重复利用,接着触发任务执行
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) {
//从正在运行的任务列表或者等待执行的任务列表中查找是否存在对相同host的请求
val existingCall = findExistingCallWithHost(call.host)
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
}
}
promoteAndExecute()
}
//将等待执行的任务队列中的任务顺序添加进入正在执行的任务队列中,并且立即执行
//如果满足条件:1,正在执行的异步任务数量没有达到上限;2.
//在正在执行的任务队列中不存在或者存在相同host的任务但是不超过规定上限的
//任务
private fun promoteAndExecute(): Boolean {
this.assertThreadDoesntHoldLock()
val executableCalls = mutableListOf<AsyncCall>()
val isRunning: Boolean
synchronized(this) {
val i = readyAsyncCalls.iterator()
while (i.hasNext()) {
val asyncCall = i.next()
//如果正在请求数量大于限制的最大值就返回
if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
//如果相同host的请求数量大于限制的最大值就跳过,执行其它任务
if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
//将该任务从等待队列中移除
i.remove()
//并且将请求次数加一,用于统计此时此刻相同host的请求一共有多少个
asyncCall.callsPerHost.incrementAndGet()
//将该任务添加进入正在运行和即将执行的列表中
executableCalls.add(asyncCall)
runningAsyncCalls.add(asyncCall)
}
isRunning = runningCallsCount() > 0
}
//开始执行满足条件的任务
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)
}
return isRunning
}
我们进入asyncCall.executeOn(executorService)这个方法
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!
}
}
}
如果执行成功会进入RealCall的execute()方法
override fun execute(): Response {
synchronized(this) {
check(!executed) { "Already Executed" }
executed = true
}
timeout.enter()
callStart()
try {
client.dispatcher.executed(this)
return getResponseWithInterceptorChain()
} finally {
client.dispatcher.finished(this)
}
}
timeout.enter()开始执行网络请求倒计时.
接着我们进入getResponseWithInterceptorChain()这个方法
internal fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
val interceptors = mutableListOf<Interceptor>()
//第三方APP传入的拦截器
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(
call = this,
interceptors = interceptors,
index = 0,
exchange = null,
request = originalRequest,
connectTimeoutMillis = client.connectTimeoutMillis,
readTimeoutMillis = client.readTimeoutMillis,
writeTimeoutMillis = client.writeTimeoutMillis
)
var calledNoMoreExchanges = false
try {
val response = chain.proceed(originalRequest)
if (isCanceled()) {
response.closeQuietly()
throw IOException("Canceled")
}
return response
} catch (e: IOException) {
calledNoMoreExchanges = true
throw noMoreExchanges(e) as Throwable
} finally {
if (!calledNoMoreExchanges) {
noMoreExchanges(null)
}
}
}
这个方法里面主要是按照拦截器添加的顺序执行所有的拦截器的
chain.proceed(originalRequest)方法,其中我们主要分析ConnectInterceptor网络连接拦截器和CallServerInterceptor向服务器发送请求拦截器
以下是ConnectInterceptor网络拦截器实现的部分
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
val exchange = realChain.call.initExchange(chain)
val connectedChain = realChain.copy(exchange = exchange)
return connectedChain.proceed(realChain.request)
}
接着我们主要分析realChain.call.initExchange(chain)这个方法
/** Finds a new or pooled connection to carry a forthcoming request and response. */
internal fun initExchange(chain: RealInterceptorChain): Exchange {
synchronized(connectionPool) {
check(!noMoreExchanges) { "released" }
check(exchange == null)
}
val codec = exchangeFinder!!.find(client, chain)
val result = Exchange(this, eventListener, exchangeFinder!!, codec)
this.interceptorScopedExchange = result
synchronized(connectionPool) {
this.exchange = result
this.exchangeRequestDone = false
this.exchangeResponseDone = false
return result
}
}
在exchangeFinder!!.find(client, chain)方法中主要做了两件事情,
第一件,在连接池中查找如果存在符合条件的连接就复用,否则自己重新创建连接;
第二件,创建Exchange对象;
接着我们进入CallServerInterceptor拦截器
它里面就做了通过Socket连接向服务器发送网络请求数据和接受服务器返回的数据.这里面代码篇幅太多就不详解了,有兴趣的朋友可以自行分析。