使用方式
创建一个OkHttpClient对象,一个Request对象,然后利用他们创建一个Call对象,最后调用同步请求execute()方法或者异步请求enqueue()方法来拿到Response。
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://github.com/")
.build();
RealCall call = client.newCall(request)
//同步请求
Response response = client.newCall(request).execute();
//异步请求
client.newCall(request).enqueue();
各步骤解析
构造OkHttpClient
它使用Builder模式来配置各种参数,如添加拦截器、代理、SSL、超时时间等,然后创建RealCall实例来处理具体的请求。
OkHttpClient client = new OkHttpClient.Builder()
.dispatcher(dispatcher)
.addNetworkInterceptor(new SignInterceptor())
.addNetworkInterceptor(new NetworkInterceptor())
.eventListenerFactory(NetworkListener.get())
.build();
构造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>
)
构造RealCall
interface Call : Cloneable {
/** 返回发起此调用的原始请求 */
fun request(): Request
/**
* 同步请求,立即执行。
*
* 抛出两种异常:
* 1. 请求失败抛出IOException;
* 2. 如果在执行过一回的前提下再次执行抛出IllegalStateException;*/
@Throws(IOException::class)
fun execute(): Response
/**
* 异步请求,将请求安排在将来的某个时间点执行。
* 如果在执行过一回的前提下再次执行抛出IllegalStateException */
fun enqueue(responseCallback: Callback)
/** 取消请求。已经完成的请求不能被取消 */
fun cancel()
/** 是否已被执行 */
fun isExecuted(): Boolean
/** 是否被取消 */
fun isCanceled(): Boolean
/** 一个完整Call请求流程的超时时间配置,默认选自[OkHttpClient.Builder.callTimeout] */
fun timeout(): Timeout
/** 克隆这个call,创建一个新的相同的Call */
public override fun clone(): Call
/** 利用工厂模式来让 OkHttpClient 来创建 Call对象 */
fun interface Factory {
fun newCall(request: Request): Call
}
}
Call接口的具体实现类,是应用与网络层之间的连接桥,包含OkHttpClient与Request信息。
在OkHttpClient中调用创建
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
同步execute或异步enqueue
构造RealCall之后就可以通过该类进行同步请求 execute() 或 异步请求 enqueue()
// 同步执行
override fun execute(): Response {
try {
client.dispatcher.executed(this)
return getResponseWithInterceptorChain()
} finally {
client.dispatcher.finished(this)
}
}
// 异步执行
override fun enqueue(responseCallback: Callback) {
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
同步请求
realCall.execute()在当前线程直接执行,通过getResponseWithInterceptorChain()构造责任链获取Response
override fun execute(): Response {
try {
return getResponseWithInterceptorChain()
}
}
异步请求
realCall.enqueue()时构造AsyncCall,实际上就是一个Runnable,有个executeOn方法,在Dispatcher中调度使用线程池中线程执行该Runnable,run中的逻辑与同步请求基本一致
fun executeOn(executorService: ExecutorService) {
try {
executorService.execute(this)
}
}
override fun run() {
threadName("OkHttp ${redactedUrl()}") {
try {
val response = getResponseWithInterceptorChain()
}
}
}
异步请求的执行策略
Dispatcher负责异步请求的执行策略
1、三个队列 readyAsyncCalls(准备中的异步调用)、runningAsyncCalls(运行中的异步调用)、runningSyncCalls(运行中的同步调用)。Dispatcher主要是负责异步请求的执行策略,所以最主要的还是readyAsyncCalls和runningAsyncCalls
private val readyAsyncCalls = ArrayDeque<AsyncCall>() // 等待队列
private val runningAsyncCalls = ArrayDeque<AsyncCall>() // 运行中的异步请求
private val runningSyncCalls = ArrayDeque<RealCall>() // 运行中的同步请求
2、线程池配置 这种线程池配置适合处理大量短生命周期的异步任务,因为当任务提交时,如果有空闲线程则复用,否则创建新线程,空闲超过60秒则回收。
executorService = ThreadPoolExecutor(
0, // 核心线程数
Int.MAX_VALUE, // 最大线程数(实际受maxRequests限制)
60, SECONDS, // 空闲线程存活时间
SynchronousQueue() // 直接传递任务
)
3、promoteAndExecute promoteAndExecute方法是关键,它负责将准备队列中的任务提升到运行队列,并提交给线程池执行。
4、 执行流程 当一个异步请求被enqueue时,首先被加入readyAsyncCalls队列。
fun enqueue(call: AsyncCall) {
synchronized {
readyAsyncCalls.add(call)
}
promoteAndExecute() // 触发任务调度
}
然后,promoteAndExecute被调用,检查当前运行中的请求数是否未超过maxRequests,并且每个主机的请求数未超过maxRequestsPerHost。如果条件满足,任务被移动到runningAsyncCalls,并通过线程池执行。
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.
if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
i.remove()
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逻辑
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)
}
请求前的拦截器
前面的execute或者enqueue最后都会到getResponseWithInterceptorChain中构造责任链,需要经过多个拦截器处理,最后一个CallServerInterceptor拦截器中会执行真正的网络请求
internal fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
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) // 最终网络IO
val chain = RealInterceptorChain(
call = this,
interceptors = interceptors,
index = 0,
exchange = null,
request = originalRequest,
connectTimeoutMillis = client.connectTimeoutMillis,
readTimeoutMillis = client.readTimeoutMillis,
writeTimeoutMillis = client.writeTimeoutMillis
)
val response = chain.proceed(originalRequest)
return response
}
链式调用机制
sequenceDiagram
participant C as Client
participant IC as InterceptorChain
participant I1 as Interceptor1
participant I2 as Interceptor2
participant NC as NetworkCall
C->>IC: 发起请求
IC->>I1: proceed()
I1->>IC: 修改请求
IC->>I2: 创建新Chain传递请求
I2->>NC: 最终执行网络请求
NC-->>I2: 返回原始响应
I2-->>IC: 返回处理后的响应
IC-->>C: 最终响应结果
RealInterceptorChain中会创建了新的chain传给intercept,在每个interceptor#intercept中会调用chain的proceed传入新的request
// Chain的proceed会创建新的chain并传递给下一个interceptor
override fun proceed(request: Request): Response {
// 创建下一个链节点
val next = copy(index = index + 1, request = request)
// 获取当前拦截器
val interceptor = interceptors[index]
// 执行拦截逻辑
return interceptor.intercept(next)
}
LoggingInterceptor封装了新的request,将其传回给chain,在chain.proceed中会将request传递给下一个interceptor
class LoggingInterceptor : Interceptor {
override fun intercept(chain: Chain): Response {
// 修改request
val request = chain.request().newBuilder()
.addHeader("X-Request-Time", System.currentTimeMillis().toString())
.build()
val response = chain.proceed(modifiedRequest)
// 修改response
return response
.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build()
}
}
class NetworkMonitorInterceptor : Interceptor {
override fun intercept(chain: Chain): Response {
val connection = chain.connection()!!
monitor.trackConnection(connection)
return chain.proceed(chain.request())
}
}
设计要点
- 不可变设计:通过copy()方法创建新chain实例保持线程安全
- 状态隔离:每个chain实例维护独立的index/calls计数器
- 防御性校验:通过严格检查保证拦截器实现符合规范
- 上下文传递:通过exchange对象携带底层网络连接信息
总结
当用户构建OkHttpClient实例并调用newCall(request)时,会创建一个RealCall,然后通过Dispatcher来管理异步请求的执行。请求会经过配置的拦截器链,最终由CallServerInterceptor发送到服务器并获取响应,再逆向返回给调用方。