本篇内容
okhttp的源码流程主要逻辑就分为两块1.分发器 2.拦截器。上篇分析一下整体流程和分发器。
okhttp的优点
- 支持http1.1、2,quic以及websocket
- 连接池复用底层tcp(socket),减少请求时延
- 支持GZIP压缩,减少流量,传输快
- 缓存数据,减少重复的网络请求
- 支持失败自动重试与重定向
okhttp整体流程图
分发器Dispatcher类配置
public final class Dispatcher {
//同时存在最大请求数
private int maxRequests = 64;
//同host最多支持请求数
private int maxRequestsPerHost = 5;
//闲置任务
private @Nullable Runnable idleCallback;
//线程池
private @Nullable ExecutorService executorService;
//异步请求等待执行队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//异步请求运行队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//同步请求执行队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
}
1.分发器
同步请求做了什么?
//只是将任务添加到了同步请求运行队列中
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
异步请求做了什么?
异步请求首先做判断,条件1小于最大请求数64(考虑客户端手机的压力),条件2同一host小于5个请求(考虑服务端的压力)
synchronized void enqueue(AsyncCall call) {
//两个判断
//最大线程数<64 同一个host小于5 才会添加到执行队列
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//添加到执行队列
runningAsyncCalls.add(call);
//线程池执行任务
executorService().execute(call);
} else {
//否则添加到等待队列
readyAsyncCalls.add(call);
}
}
//线程池配置
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
2.同步请求流程
//构造request请求
Request request = new Request.Builder()
.url("http://baidu.com")
.build();
//构造okhttpclient对象
OkHttpClient okHttpClient = new OkHttpClient()
.newBuilder()
.build();
//构造runnable call对象
Call call = okHttpClient.newCall(request);
try {
//调用同步方法
call.execute();
} catch (IOException e) {
e.printStackTrace();
}
//call是接口,真正的实现类是RealCall
@Override public Response execute() throws IOException {
try {
//使用分发器方法 上面的分发器中已经说过只是将任务加入了同步执行队列,只是记录一下。
client.dispatcher().executed(this);
//*****************************************
//真正请求的方法是getResponseWithInterceptorChain
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
//这一步知道从拦截器链中获取响应就好了,拦截器在下一篇详细讲解
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
//省略
}
流程大概如下,不纠结细节代码。
3.异步请求流程
//构造request请求
Request request = new Request.Builder()
.url("http://baidu.com")
.build();
//构造okhttpclient对象
OkHttpClient okHttpClient = new OkHttpClient()
.newBuilder()
.build();
//构造runnable call对象
Call call = okHttpClient.newCall(request);
//异步请求,添加请求回调方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
//添加到分发器中Dispatcher
client.dispatcher().enqueue(new AsyncCall(responseCallback));
synchronized void enqueue(AsyncCall call) {
//两个判断
//最大线程数<64 同一个host小于5 才会添加到执行队列
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//添加到执行队列
runningAsyncCalls.add(call);
//线程池执行任务
executorService().execute(call);
} else {
//否则添加到等待队列
readyAsyncCalls.add(call);
}
}
到这里分发器的工作基本上已经说完了。