OkHttp 核心源码解析:分发器与拦截器的责任链之旅

6 阅读8分钟

OkHttp 核心源码解析:分发器与拦截器的责任链之旅

本文基于 OkHttp 4.x 源码,以一次异步 enqueue 请求为主线,拆解 OkHttp 两大核心模块:Dispatcher(分发器) 和 Interceptor(拦截器链)。


目录


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;
}

关键逻辑:

  1. 遍历准备队列
  2. 检查 runningAsyncCalls.size() >= maxRequests(64)?是则停止
  3. 检查 callsPerHost >= maxRequestsPerHost(5)?是则跳过这个请求
  4. 通过后:从准备队列移除 → 加入执行队列 → 调 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 的区别

addInterceptoraddNetworkInterceptor
触发时机在 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 桥接。


上一篇:Retrofit 核心调用链源码解析:从动态代理到 OkHttp