整体架构
Interface——接口层:接受网络访问请求
Protocol——协议层:处理协议逻辑
Connection——连接层:管理网络连接,发送新的请求,接收服务器访问
Cache——缓存层:管理本地缓存
I/O——I/O层:实际数据读写实现
Inteceptor——拦截器层:拦截网络访问,插入拦截逻辑
官方文档是这样描述OkHttp
- OkHttp is an HTTP client that’s efficient by default:
- HTTP/2 support allows all requests to the same host to share a socket.
- Connection pooling reduces request latency (if HTTP/2 isn’t available).
- Transparent GZIP shrinks download sizes.
- Response caching avoids the network completely for repeat requests.
OkHttp是一个高效的HTTP客户端,拥有以下特性:
- HTTP/2支持对同一主机的所有请求共享套接字。
- 使用连接池减少请求延迟(如果HTTP/2不可用)。
- 透明GZIP减少下载大小。
- 响应缓存可以完全避免网络重复请求。
核心类
okhttp3.OkHttpClient:全局配置与网络操作入口
okhttp3.Request:一次网络请求的url、body、header等
okhttp3.Response:一次网络请求的响应
okhttp3.RealCall:代表一个OkHttp封装的实际网络操作实例
okhttp3.Dispatcher:操作okhttp3.RealCall,连接池,异步请求线程池封装
okhttp3.Callback:异步请求的callback
okhttp3.RealCall.AsyncCall#AsyncCall:对于okhttp3.Callback的封装,继承NamedRunnable实现Runnable接口,是OkHttp实现异步网络请求的重要组成部分
okhttp3.internal.connection.Transmitter:
okhttp3.internal.connection.Exchange:
okhttp3.internal.Internal:
1.1 调用
OkHttp提供了两种调用方式:
同步调用
异步调用
1.1.1 同步调用
okhttp3.OkHttpClient#newCall(Request request)# execute() -> okhttp3.RealCall#execute
public Response execute() throws IOException {
synchronized(this) {
if (this.executed) {
throw new IllegalStateException("Already Executed");
}
this.executed = true;
}
this.transmitter.timeoutEnter();
this.transmitter.callStart();
Response var1;
try {
this.client.dispatcher().executed(this);
var1 = this.getResponseWithInterceptorChain();
} finally {
this.client.dispatcher().finished(this);
}
return var1;
}
- 加锁,打上标记位(this.executed = true),避免多次调用RealCall#execute
- 将RealCall加入到同步队列
3.this.client.dispatcher().executed(this)
4.OkHttpClient.Dispatcher.runningSyncCalls.add(call)
5.调用getResponseWithInterceptorChain实际执行HTTP请求 - 从同步队列中删除
- this.client.dispatcher().finished
8.OkHttpClient.Dispatcher.runningSyncCalls.remove(call)
1.1.2 异步调用
okhttp3.OkHttpClient#newCall(Request request)# enqueue (Callback ) responseCallback) -> okhttp3.RealCall#enqueue
[endif]加锁,打上标记位(this.executed = true),避免多次调用RealCall#execute
-
将Callback封装成AsyncCall,放入到异步执行队列中
- readyAsyncCalls#add
- AsyncCall继承NamedRunnable,也就实现了Runnable接口
- 调用Dispatcher#promoteAndExecute
2 OkHttp异步网络请求的实现
从1.1.2中已经有一个简单的异步请求分析,一个异步请求(AsyncCall)的AsyncCall#execute方法最终会被调用,在执行拦截器Chain后得到Response。
3 拦截器
从第2节中,已经可以看到发起一个请求的重要代码是
AsyncCall#execute(异步) OR RealCall#execute(同步),其中的核心是
1.获取并执行拦截器Chain得到Response- getResponseWithInterceptorChain
2.通知分发器任务完成- client.dispatcher().finished
在不考虑异常的情况下,OkHttp发起一个HTTP请求,实际的网络操作都在getResponseWithInterceptorChain方法中体现。
3.1 构造拦截器链
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List interceptors = new ArrayList<>();
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) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
Response response = chain.proceed(originalRequest);
…
}
其中主要逻辑分为两部分
1.创建一系列的拦截器,包括系统内置与用户自定义的拦截器
2.创建RealInterceptorChain,并执行proceed方法得到Response
拦截器顺序是
自定义拦截器(interceptors)
RetryAndFollowUpInterceptor
BridgeInterceptor
CacheInterceptor
ConnectInterceptor
自定义网络拦截器(networkInterceptors)
CallServerInterceptor
那么RealInterceptorChain#proceed做了什么呢?
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
return response;
可以看到主要也是两部分
创建下一个RealInterceptorChain,指明下一个执行的拦截器索引为index + 1
执行(调用intercept)索引为index的拦截器
接下来从系统内置第一个拦截器RetryAndFollowUpInterceptor为例,看看在intercept方法中做了什么。
从名字中我们可以看出,这个拦截器的主要作用应该是处理请求的重试与重定向。
3.2 内置拦截器责则
RetryAndFollowUpInterceptor
在网络请求失败后进行重试
当服务器返回当前请求需要进行重定向时直接发起新的请求,并在条件允许情况下复用当前连接
BridgeInterceptor
设置内容长度、编码
设置内容长度,内容编码
添加cookie
设置一些http head,例如User-Agent: okhttp/3.14.2; keep-Alive等、
CacheInterceptor
当网络请求有符合要求的Cache时直接返回Cache
当服务器返回内容有改变时更新当前cache
如果当前cache失效,删除
ConnectInterceptor
- 负责找到一个合适的Connection。其中ExchangeCodec持有一个可用的Connection。
重点代码:
exchangeFinder->okhttp3.internal.connection.Transmitter#prepareToConnect->
由RetryAndFollowUpInterceptor触发
ExchangeCodec codec = exchangeFinder.find(client, chain, doExtensiveHealthChecks);
Exchange result = new Exchange(this, call, eventListener, exchangeFinder, codec);
CallServerInterceptor
负责向服务器发起真正的访问请求,并在接收到服务器返回后读取响应返回。
3.3 请求拦截链的整体流程
--TODO
4 任务队列(异步请求线程池)
在前面的分析中已经提及Dispatcher类是用于操作okhttp3.RealCall,对连接池,异步请求线程池封装。
与任务队列相关的字段:
readyAsyncCalls:待执行异步任务队列
runningAsyncCalls:运行中异步任务队列
runningSyncCalls:运行中同步任务队列
executorService:任务队列线程池
从代码可以看到,构建了一个线程池corePoolSize是0,最大线程数是Integer.MAX_VALUE,空闲时间是60秒,阻塞队列使用SynchronousQueue,这个阻塞队列不储存元素。
因此该线程池是来一个请求就会创建一个线程,当线程空闲60s后会被回收,由于corePoolSize是0,那么当60s没有新的请求,所有的线程都会给回收。
5 缓存策略
TO DO
6 连接池
在OkHttp中使用okhttp3.ConnectionPool来管理连接池,在okhttp3.ConnectionPool内部使用okhttp3.internal.connection.RealConnectionPool delegate来实际管理连接池。
okhttp3.internal.connection.RealConnectionPool
主要字段:
Executor executor:用于清除失效连接线程池
int maxIdleConnections:最大闲置连接数
long keepAliveDurationNs:keep alive时间
Runnable cleanupRunnable:清除失效连接
boolean cleanupRunning:put的时候设置为true,清除失效连接之后设置为false
Deque
RouteDatabase routeDatabase:
主要方法:
int idleConnectionCount():统计idle的connection数
boolean transmitterAcquirePooledConnection:尝试复用一个Connection并关联上transmitter
void put(RealConnection connection):添加一个Connection,并触发cleanup线程
boolean connectionBecameIdle(RealConnection connection):当一个Connection空闲根据条件判断唤醒cleanup线程或者直接remove这个Connection
void evictAll():扫描并关闭所有空闲连接
long cleanup(long now):实际进行清除失效连接操作
int pruneAndGetAllocationCount():标记泄露的连接
void connectFailed():连接失败
相关类
okhttp3.internal.connection.RealConnection
封装物理连接
List
okhttp3.internal.connection.Transmitter
okhttp3.internal.connection.RouteDatabase
用来记录连接失败的Route的黑名单,当连接失败的时候就会把失败的线路加进去
7 类分析
7.1 okhttp3.internal.connection.Transmitter
Bridge between OkHttp's application and network layers. This class exposes high-level application layer primitives: connections, requests, responses, and streams.
OkHttp应用和网络层的桥梁。这个类暴露高级应用层的原语:连接,请求,响应,流
附录
项目地址:https://github.com/square/okhttp
项目文档:https://github.com/square/okhttp/wiki
Easy OkHttp(对OkHttp的封装):https://gitee.com/yuanzizhenxin/easy-okhttp
源码分析(OkHttp 3.7):https://yq.aliyun.com/articles/78105