OkHttp使用流程
首先看一下OkHttp大概的使用流程:
1.创建OkHttpClient对象,使用默认配置或用建造者模式进行自己的配置
2.client作为网络请求器,把请求Request交给他,得到随时可以工作的Call对象(Call是接口,实现类是RealCall)
3.Call的execute或enqueue
4.给到分发器Dispatcher。
分发器:内部维护队列与线程池,完成请求调配。发送一个http请求,再发一个要等待上一个请求完成第二个才能执行吗?所以要用到并发,用到线程池。
5.再给到拦截器Interceptors。
拦截器:五大默认拦截器完成整个请求过程。
6.通过后把请求给服务器得到Response,再给拦截器再给用户。
分发器解析
我们先主要来看分发器
Call是什么,拿call.enqueue()来看。newCall()里面新建了RealCall对象,然后是RealCall.enqueue()。
enqueue需要一个Callback,可以告诉我们请求有了响应或是失败
每次请求都会新建一个Call对象,每个Call只能执行一次,如果再次执行,会抛出异常
void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}
然后得到client的分发器,当然分发器可自己定义,其实默认的足够。然后新建AsyncCall交给dispatcher,去执行enqueue()方法。
异步有两个队列,一个Ready,一个Running队列(都是双端队列ArrayQueue,但目前没有用到双端)。等一会执行或马上执行
问题一: 如何决定将请求放入ready队列(readyAsyncCalls)还是running队列(runningAsyncCalls)?
Dispatcher的enqueue()方法。如果运行队列中任务数(正在执行的请求)小于64 ,并且正在执行的队列里面与现在的请求的Host相同的有5个以下(也就是相同Host的请求不能超过5个),放入running队列,否则放入ready队列。(前者客户端压力,后者服务器压力,并且可以通过setMaxRequests()与setMaxRequestsPerHost()方法去修改)
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);//线程池马上跑任务,ThreadPool
} else {
readyAsyncCalls.add(call);
}
}
问题二: ready队列里的何时执行?
任务执行完,AsyncCall中的execute()中的finally->分发器的finished():将call从running队列中移除,考虑从ready队列中获取任务放入到running队列中(promoteCalls())
synchronized void finished(AsyncCall call) {
if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
promoteCalls();
}
private void promoteCalls() {
//若队列任务大于等于64,退!若ready队列空,退!
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
//遍历,还有一个限制!对同一Host的请求要小于5。然后放满了就不放了
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
同步请求的话比较简单,没有什么限制。dispatcher的executed方法。
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
RealCall execute()的finally中finished()方法
void finished(RealCall call) {
finished(runningSyncCalls, call);
}
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();
}
}
同步请求队列是runningSyncCalls。异步请求队列有runningAsyncCalls和readyAsyncCalls。