源码解析"/>
OkHttp3 源码解析
参考地址
调用方式
同步调用
@Override public Response execute() throws IOException {synchronized (this) {if (executed) throw new IllegalStateException("Already Executed");executed = true;}try {client.dispatcher().executed(this);Response result = getResponseWithInterceptorChain(false);if (result == null) throw new IOException("Canceled");return result;} finally {client.dispatcher().finished(this);}
}
异步调用
void enqueue(Callback responseCallback, boolean forWebSocket) {synchronized (this) {if (executed) throw new IllegalStateException("Already Executed");executed = true;}client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}
总体架构
接口层
OKHttpClient 全局维护一个实例,对全局OkHttp 进行设置
Call 表示一次请求执行,分为同步的ReallCall及AsyncCall
协议层
处理特定的协议逻辑,OkHttp支持Http1/Http2/WebSocket协议
连接层
管理网络连接,网络连接请求,服务返回
- RealConnection 描述一个Socket的连接请求。ConnectionPool 缓存了多个Connection。
- StreamAllocation表示一次全新的网络请求(一个Call请求可能包含有多个StreamAllocation ,比如重定向)
缓存层
管理本地缓存,当本地有可用缓存时,直接采用本地的以节约流量
I/O层
表示数据的实际读写,采用OKIO
Iterceptor 拦截器层
拦截器逻辑
首先由getResponseWithInterceptorChain 把系统及自定义的拦截器传入
Response getResponseWithInterceptorChain() throws IOException {// Build a full stack of interceptors.List<Interceptor> interceptors = new ArrayList<>();interceptors.addAll(client.interceptors());interceptors.add(retryAndFollowUpInterceptor);interceptors.add(new BridgeInterceptor(client.cookieJar()));interceptors.add(new CacheInterceptor(client.internalCache()));interceptors.add(new ConnectInterceptor(client));if (!forWebSocket) {interceptors.addAll(clientworkInterceptors());}interceptors.add(new CallServerInterceptor(forWebSocket));Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest);return chain.proceed(originalRequest);}
调用 RealInterceptorChain 的process 方法轮训每个拦截器
public final class RealInterceptorChain implements Interceptor.Chain {public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,RealConnection connection) throws IOException {......// Call the next interceptor in the chain.RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec, connection, index + 1, request);Interceptor interceptor = interceptors.get(index);Response response = interceptor.intercept(next);...... return response;}
}
RetryAndFollowUpInterceptor
- 访问失败后进行重试
- 对服务器要求重定向的情况下进行连接复用
BridgeIterceptor
- 设置内容长度及类型
- 设置cookie
- 设置gzip并在获取response 后进行释放
- 设置其他报头
CacheInterceptor
- 增加符合网络要求的cache
- 更新服务器的最新cache
- 当前cache失效则输出cache
ConnectInterceptor
CallServerInterceptor
整体流程
任务队列
同步
直接执行
异步队列
client.newCall(request).enqueue();
// 具体执行
synchronized void enqueue(AsyncCall call) {if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {//添加正在运行的请求runningAsyncCalls.add(call);//线程池执行请求executorService().execute(call);} else {//添加到缓存队列排队等待readyAsyncCalls.add(call);}
}
- 若线程数未达到最大请求则通过线程池直接执行
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
- 若线程数达到最大请求则加入等待队列,当其他线程执行完成后调用client.dispatcher().finished(this); 来继续执行等待的队列
缓存
Http 缓存策略
- Expires 超时时间,当访问服务器时比较超时时间,若未超过直接返回缓存结果
- Cache-Control 表示当前资源的有效期
- 条件GET请求
客户端第一次请求时,服务器返回:Last-Modified: Tue, 12 Jan 2016 09:31:27 GMT
当客户端二次请求时,可以头部加上如下header:If-Modified-Since: Tue, 12 Jan 2016 09:31:27 GMT
如果当前资源没有被二次修改,服务器返回304告知客户端直接复用本地缓存。
- Etag
ETag是对资源文件的一种摘要,可以通过ETag值来判断文件是否有修改。当客户端第一次请求某资源时,服务器返回:ETag: "5694c7ef-24dc"
客户端再次请求时,可在头部加上如下域:If-None-Match: "5694c7ef-24dc"
如果文件并未改变,则服务器返回304告知客户端可以复用本地缓存。
更多推荐
OkHttp3 源码解析
发布评论