OkHttp 原理
·
一、核心设计思想
OkHttp 的核心架构是 “请求分发 + 拦截器链” 模式,主要基于以下几个设计模式:
| 设计模式 | 应用场景 |
|---|---|
| 建造者模式 | OkHttpClient 和 Request 的构建 |
| 门面模式 | OkHttpClient 作为统一入口,隐藏内部复杂性 |
| 责任链模式 | 拦截器链,将请求的发送者和接收者解耦 |
责任链模式是 OkHttp 的精髓——将网络请求的各个阶段封装到不同的拦截器中,串成一条链,请求沿着链依次传递,每个拦截器各司其职。
二、整体架构流程
2.1 三个核心角色
使用 OkHttp 发起请求时,最少涉及三个角色:
OkHttpClient:全局配置容器(代理、SSL、超时、缓存等),建议作为单例Request:封装 URL、Header、Body 等请求信息Call(实际为RealCall):代表一个已准备好执行的请求,通过client.newCall(request)获得
2.2 Dispatcher(分发器)
Dispatcher 负责请求的调度管理,内部包含:
| 成员 | 说明 | 默认值 |
|---|---|---|
maxRequests | 最大并发请求数 | 64 |
maxRequestsPerHost | 单域名最大并发数 | 5 |
readyAsyncCalls | 异步等待队列 | — |
runningAsyncCalls | 异步执行队列 | — |
runningSyncCalls | 同步执行队列 | — |
executorService | 线程池 | 类似 CachedThreadPool |
同步请求:直接加入 runningSyncCalls 记录,由调用方线程执行。
异步请求:判断是否超过并发限制——未超过则加入执行队列并提交线程池;超过则先进入等待队列。每次请求完成后,Dispatcher.finished() 会触发等待队列中的任务出队执行。
三、拦截器链(核心)
getResponseWithInterceptorChain() 是 OkHttp 最核心的方法,它按顺序构建拦截器列表:
3.1 各拦截器职责
| 拦截器 | 职责 |
|---|---|
| 应用拦截器(自定义) | 用户添加,最先执行,可处理公共参数、Header 等 |
| RetryAndFollowUpInterceptor | 连接失败自动重试、处理重定向 |
| BridgeInterceptor | 补全请求头(Content-Type、Content-Length、Host、Cookie 等),解压 GZIP 响应 |
| CacheInterceptor | 根据 HTTP 缓存策略,判断是否使用缓存 |
| ConnectInterceptor | 从连接池获取或新建 TCP 连接 |
| 网络拦截器(自定义) | 用户添加,在连接建立后、数据读写前执行,常用于监控网络层数据 |
| CallServerInterceptor | 最后一个拦截器,通过 HttpCodec 向服务器写出请求数据、读取响应数据 |
3.2 责任链传递机制
每个拦截器的 intercept(Chain chain) 方法分为三部分:
- 预处理:处理当前拦截器自身的逻辑
- 传递:调用
chain.proceed(request)将请求交给下一个拦截器 - 后处理:下一个拦截器返回 Response 后的后续处理
四、连接池与连接复用
TCP 连接需要三次握手,开销较大。OkHttp 通过 连接池(ConnectionPool) 复用 TCP 连接来减少延迟。
4.1 连接复用的关键点
Address:由 URL 的 Scheme、Host、Port 以及OkHttpClient的配置(如 HTTPS 设置)共同决定。相同Address的请求可共享同一个 Socket 连接。- 连接池策略:请求完成后连接不立即关闭,而是放回连接池供后续复用。
- 清理机制:连接池有后台清理线程,定期关闭闲置连接。
4.2 应用拦截器 vs 网络拦截器
面试常见问题:
| 应用拦截器 | 网络拦截器 | |
|---|---|---|
| 执行时机 | 最早执行,在重试和重定向之前 | 在 ConnectInterceptor 之后、CallServerInterceptor 之前 |
| 调用次数 | 只调用一次 | 可能调用多次(每次重试/重定向都会调用) |
| 适用场景 | 公共参数注入、日志打印 | 网络监控、流量统计 |
五、面试回答要点总结
回答“OkHttp 原理”时,可以按以下逻辑串联:
-
一句话概括:OkHttp 基于责任链模式,通过拦截器链处理请求的各个阶段,配合Dispatcher调度请求,连接池复用 TCP 连接。
-
流程简述:
OkHttpClient+Request→RealCall→execute()/enqueue()→Dispatcher调度 →getResponseWithInterceptorChain()→ 拦截器链依次处理 → 返回Response。 -
亮点展开(挑 1-2 个深入):
- 拦截器链:7 个拦截器的职责和顺序
- 连接池:
Address决定连接复用,减少三次握手开销 - Dispatcher:并发控制(64/5)和线程池调度
更多推荐



所有评论(0)