OkHttp 核心源码解析:分发器与拦截器的责任链之旅
本文基于 OkHttp 4.x 源码,以一次异步
enqueue请求为主线,拆解 OkHttp 两大核心模块:Dispatcher(分发器) 和 Interceptor(拦截器链)。
目录
- 1. 总体架构
- 2. 使用入门:四步走
- 3. RealCall 的诞生
- 4. Dispatcher 分发器
- 5. AsyncCall 的执行
- 6. 拦截器责任链
- 7. 常见面试题
- 8. 完整调用链回放
- 9. 总结
1. 总体架构
OkHttp 的核心由两大块构成:
┌─────────────────────────────────────────────────┐
│ OkHttpClient │
│ 构建者模式配置:超时、拦截器、Cookie、缓存等 │
└────────────────────┬────────────────────────────┘
│ newCall(request)
▼
┌─────────────────────────────────────────────────┐
│ RealCall │
│ 保存 client 和 request,不做事 │
└────────────────────┬────────────────────────────┘
│ enqueue / execute
▼
┌─────────────────────────────────────────────────┐
│ Dispatcher │ ← 分发器
│ 内部维护队列 + 线程池,完成请求调度 │
└────────────────────┬────────────────────────────┘
▼
┌─────────────────────────────────────────────────┐
│ Interceptor Chain │ ← 拦截器链
│ 责任链模式:五大拦截器依次处理 │
│ RetryAndFollowUp → Bridge → Cache │
│ → Connect → CallServer │
└─────────────────────────────────────────────────┘
2. 使用入门:四步走
// 第一步:创建 OkHttpClient(构建者模式)
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(null)
.connectTimeout(10, TimeUnit.SECONDS)
.build()
// 第二步:创建 Request(构建者模式)
val request = Request.Builder()
.url("https://baidu.com")
.addHeader("token", "123")
.get()
.build()
// 第三步:创建 Call 对象(实际是 RealCall)
val call = okHttpClient.newCall(request)
// 第四步:发起异步请求
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
// 请求失败
}
override fun onResponse(call: Call, response: Response) {
// 请求成功
}
})
看似简单的四步,每一层背后都有精妙的设计。下面逐层拆解。
3. RealCall 的诞生
// OkHttpClient.java
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
// RealCall.java
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.transmitter = new Transmitter(client, call);
return call;
}
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
}
RealCall 本身只是保存了 client 和 request,不做事。同时创建了一个 Transmitter,它在后续连接管理中扮演重要角色。
4. Dispatcher 分发器
4.1 三大队列与两个限制
public final class Dispatcher {
// 最大并发请求数(默认为 64)
@get:Synchronized var maxRequests = 64
// 同一主机最大并发数(默认为 5)
@get:Synchronized var maxRequestsPerHost = 5
// 准备队列 — 等待中的请求
private val readyAsyncCalls = ArrayDeque<AsyncCall>()
// 异步执行队列 — 正在执行的请求
private val runningAsyncCalls = ArrayDeque<AsyncCall>()
// 同步执行队列 — 同步请求
private val runningSyncCalls = ArrayDeque<RealCall>()
}
打个比方:
maxRequests = 64— 快递公司总共只有 64 辆车maxRequestsPerHost = 5— 发往北京的快递最多 5 辆车readyAsyncCalls— 在仓库打包中的快递runningAsyncCalls— 已经发车在路上的快递
4.2 enqueue 入队逻辑
// RealCall.java
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
// 关键一行:将 callback 包装成 AsyncCall,交给 Dispatcher
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
// Dispatcher.java
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call); // 先加入准备队列
// ...
}
promoteAndExecute(); // 尝试晋升到执行队列
}
4.3 promoteAndExecute 执行晋升
private boolean promoteAndExecute() {
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
// 超过最大并发 → 停止遍历
if (runningAsyncCalls.size() >= maxRequests) break;
// 超过同一主机最大连接 → 跳过这个,看下一个
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue;
// 通过检查:移出准备队列,加入执行队列
i.remove();
asyncCall.callsPerHost().incrementAndGet();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
// 遍历执行队列,真正开始请求
for (int i = 0; i < executableCalls.size(); i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
关键逻辑:
- 遍历准备队列
- 检查
runningAsyncCalls.size() >= maxRequests(64)?是则停止 - 检查
callsPerHost >= maxRequestsPerHost(5)?是则跳过这个请求 - 通过后:从准备队列移除 → 加入执行队列 → 调
executeOn(线程池)
4.4 finished 任务完成
// 在 AsyncCall.execute() 执行完后被调用
private <T> void finished(Deque<T> calls, T call) {
Runnable idleCallback;
synchronized (this) {
// 从执行队列移除
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
idleCallback = this.idleCallback;
}
// 再次触发晋升,让等待队列中的请求有机会执行
boolean isRunning = promoteAndExecute();
if (!isRunning && idleCallback != null) {
idleCallback.run(); // 所有请求完成,回调
}
}
核心设计: 一个请求完成后,不是直接结束,而是主动触发下一轮 promoteAndExecute,让准备队列中的请求有机会执行。这就是 OkHttp 能维持并发上限的同时最大化吞吐量的原因。
5. AsyncCall 的执行
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
private volatile AtomicInteger callsPerHost = new AtomicInteger(0);
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
// 被 Dispatcher 调用,传入线程池
void executeOn(ExecutorService executorService) {
boolean success = false;
try {
executorService.execute(this); // 线程池执行 → 触发 run() → 触发 execute()
success = true;
} catch (RejectedExecutionException e) {
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
client.dispatcher().finished(this);
}
}
}
// NamedRunnable.run() → 调这个方法
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
// ⭐ 核心:通过拦截器链获取响应
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
} catch (IOException e) {
if (signalledCallback) {
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} catch (Throwable t) {
// ...
} finally {
// 请求结束,通知 Dispatcher
client.dispatcher().finished(this);
}
}
}
执行链路:
线程池.execute(asyncCall)
↓
NamedRunnable.run()
↓
AsyncCall.execute()
├── getResponseWithInterceptorChain() ← 重点
├── responseCallback.onResponse() ← 回调成功
└── dispatcher.finished(this) ← 通知分发器
6. 拦截器责任链
6.1 五大默认拦截器
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
// ① 用户自定义的应用拦截器(addInterceptor)
interceptors.addAll(client.interceptors());
// ② 重试和重定向拦截器
interceptors.add(new RetryAndFollowUpInterceptor(client));
// ③ 桥接拦截器
interceptors.add(new BridgeInterceptor(client.cookieJar()));
// ④ 缓存拦截器
interceptors.add(new CacheInterceptor(client.internalCache()));
// ⑤ 连接拦截器
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
// ⑥ 用户自定义的网络拦截器(addNetworkInterceptor)
interceptors.addAll(client.networkInterceptors());
}
// ⑦ 服务端请求拦截器(最终执行者)
interceptors.add(new CallServerInterceptor(forWebSocket));
// 创建责任链,index = 0
RealInterceptorChain chain = new RealInterceptorChain(
interceptors, transmitter, null, 0,
originalRequest, this, ...);
return chain.proceed(originalRequest);
}
每个拦截器的职责:
| 拦截器 | 职责 |
|---|---|
| 应用拦截器 | 用户自定义,最外层,一次调用只经过一次 |
| RetryAndFollowUpInterceptor | 重试(最多 20 次)和重定向;创建 ExchangeFinder 管理连接 |
| BridgeInterceptor | 添加请求头(Content-Type、Content-Length、Host、Cookie 等);Gzip 压缩/解压 |
| CacheInterceptor | 缓存策略,使用 OkIO 进行缓存读写 |
| ConnectInterceptor | 建立连接,通过 RealConnection 创建 Socket,优先复用连接池 |
| 网络拦截器 | 用户自定义,每次真实网络请求都触发(包含重定向后的请求) |
| CallServerInterceptor | 最终执行者,真正读写 HTTP 数据 |
6.2 责任链源码解析
// RealInterceptorChain.java
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
// 构建下一个责任链节点(index + 1)
RealInterceptorChain next = new RealInterceptorChain(
interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
// 取出当前拦截器
Interceptor interceptor = interceptors.get(index);
// 调用当前拦截器,传入 nextChain
Response response = interceptor.intercept(next);
return response;
}
核心逻辑只有三步:
1. index + 1 构建 nextChain
2. 按 index 取出当前拦截器
3. 调 intercept(nextChain),等待结果返回
拿 RetryAndFollowUpInterceptor 举例:
public final class RetryAndFollowUpInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
try {
// 调 nextChain.proceed,把请求往下传,等结果回来
response = realChain.proceed(request, transmitter, null);
success = true;
} catch (RouteException e) {
// 连接失败 → 重试
if (!recover(...)) throw e;
continue;
}
// 检查是否需要重定向,可能需要重新发起请求
// ...
}
}
6.3 一个生动的类比
我要请假,向主管提审批。
- 3 天内 → 主管直接批了
- 超出 3 天 → 主管流转到经理那等审批
- 经理同意了 → 主管收到审批结果后,经理都同意了,自己也没意见,回复同意
这就是责任链工作流。
对应到 OkHttp:
用户代码 → [应用拦截器] → [RetryAndFollowUp] → [Bridge] → [Cache]
→ [Connect] → [网络拦截器] → [CallServer] ← 最终执行
← 结果一层层往上返回
← ...
← 最终回到用户代码
7. 常见面试题
addInterceptor vs addNetworkInterceptor 的区别
addInterceptor | addNetworkInterceptor | |
|---|---|---|
| 触发时机 | 在 OkHttp 核心拦截器之前 | 在 OkHttp 核心拦截器之后 |
| 触发次数 | 一次(不管重定向/重试) | 可能多次(每次真实网络请求都触发) |
| 能否看到缓存命中? | 能看到(在 CacheInterceptor 之前) | 看不到(在 CacheInterceptor 之后) |
使用场景:
addInterceptor→ 添加公共请求头、鉴权 token、自定义缓存策略addNetworkInterceptor→ 日志打印、网络调试、统计每次真实网络请求
8. 完整调用链回放
拿一次 call.enqueue(callback) 走一遍:
call.enqueue(callback)
↓
RealCall.enqueue(callback)
├── 检查是否已执行(只能执行一次)
└── client.dispatcher().enqueue(new AsyncCall(callback))
↓
Dispatcher.enqueue(asyncCall)
├── readyAsyncCalls.add(asyncCall) ← 先加入准备队列
└── promoteAndExecute()
↓
Dispatcher.promoteAndExecute()
├── 遍历 readyAsyncCalls
├── 检查 maxRequests(64)→ 通过
├── 检查 maxRequestsPerHost(5)→ 通过
├── readyAsyncCalls.remove(asyncCall)
├── runningAsyncCalls.add(asyncCall)
└── asyncCall.executeOn(线程池)
↓
AsyncCall.executeOn(线程池)
└── 线程池.execute(this)
↓
AsyncCall.execute() ← 在子线程中执行
├── getResponseWithInterceptorChain()
│ ↓
│ RealInterceptorChain.proceed(request)
│ ├── [应用拦截器] → chain.proceed
│ ├── [RetryAndFollowUp] → 重试/重定向逻辑 → chain.proceed
│ ├── [BridgeInterceptor] → 添加请求头 → chain.proceed
│ ├── [CacheInterceptor] → 缓存策略 → chain.proceed
│ ├── [ConnectInterceptor] → 建立 TCP 连接 → chain.proceed
│ ├── [网络拦截器] → chain.proceed
│ └── [CallServerInterceptor] → 真正读写 HTTP
│ ↓
│ 响应一层层返回
│
├── responseCallback.onResponse(response) ← 回调成功
└── client.dispatcher().finished(this)
↓
Dispatcher.finished()
├── runningAsyncCalls.remove(asyncCall) ← 从执行队列移除
├── promoteAndExecute() ← 触发下一个请求
└── idleCallback?.run() ← 全部完成时触发
时序图
调用方 RealCall Dispatcher AsyncCall 拦截器链 OkHttp
│ │ │ │ │ │
│ enqueue(cb) │ │ │ │ │
│──────────────►│ │ │ │ │
│ │ dispatcher │ │ │ │
│ │ .enqueue() │ │ │ │
│ │──────────────►│ │ │ │
│ │ │ ready队列 │ │ │
│ │ │──────────────►│ │ │
│ │ │ promote&Exec │ │ │
│ │ │──────────────►│ │ │
│ │ │ │ executeOn │ │
│ │ │ │ (线程池) │ │
│ │ │ │──────┐ │ │
│ │ │ │ │ 子线程 │
│ │ │ │◄─────┘ │ │
│ │ │ │ execute() │ │
│ │ │ │─────────────►│ │
│ │ │ │ │ chain │
│ │ │ │ │ .proceed() │
│ │ │ │ │─────────────►│
│ │ │ │ │ │
│ │ │ │ │ 网络响应 │
│ │ │ │ │◄─────────────│
│ │ │ │◄─────────────│ │
│ │ │ │ │ │
│ │ │ finished() │ │ │
│ │ │◄──────────────│ │ │
│ │ │ promote&Exec │ │ │
│ │ │ (下一个请求) │ │ │
│ onResponse │ │ │ │ │
│◄──────────────│ │ │ │ │
9. 总结
OkHttp 的两种核心模块
| 模块 | 职责 | 关键类 |
|---|---|---|
| Dispatcher(分发器) | 请求调度与并发控制 | Dispatcher、AsyncCall |
| Interceptor(拦截器链) | 请求处理流水线 | RealInterceptorChain、五大拦截器 |
Dispatcher 的核心设计
三条队列:
readyAsyncCalls → 等待中的请求
runningAsyncCalls → 正在执行的异步请求
runningSyncCalls → 正在执行的同步请求
两个限制:
maxRequests = 64 → 最大并发数
maxRequestsPerHost → 同一主机最大连接数(默认 5)
一个关键循环:
enqueue → promoteAndExecute → finished → promoteAndExecute(循环)
拦截器链的核心设计
责任链模式:
index 递增 → 每个拦截器持有 nextChain → 调用 intercept(nextChain)
→ 层层向下 → 最终 CallServerInterceptor 执行 → 结果层层返回
七大节点:
应用拦截器 → RetryAndFollowUp → Bridge → Cache → Connect
→ 网络拦截器 → CallServer
一句话总结
OkHttp 的核心就是:Dispatcher 决定什么时候发请求(并发控制),Interceptor Chain 决定怎么处理和发送请求(请求处理流水线),两者通过 AsyncCall 桥接。