应用层:
1.讲请求添加到分发起中 Client.dispatcher().executed(this);
2.创建截获器ApplicationInterceptorChain(可对请求进行压缩,修改编码等处理)
逻辑层
1.数据缓存:
1)缓存的数据没有过期,直接使用
2)缓存的数据过期,先用过期的,再去网络请求数据,并更新本地数据
3)缓存的数据没有,去网络直接获取
2.底层使用连接池
3.路线选择器(路由选择,选择最优)
4.网络截获器可以有多个(依据目标地址是否有重定向来觉得)
链路层
1.底层是Socket
1 概述
1.1 线程池ThreadPoolExecutor
ThreadPoolExecutor是java线程创建工具。存在于java.util.concurrent 包中。
看构造方法:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue)
okhttp的线程池对象存在于Dispatcher类中。实例过程如下:
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
1.2 Call对象
okttp的操作元是Call对象。异步的实现是RealCall.AsyncCall。而 AsyncCall是实现的一个Runnable接口。所以Call本质就是一个Runable线程操作元肯定是放进excutorService中直接启动的。
final class AsyncCall extends NamedRunnable {}
private final Deque readyAsyncCalls = new ArrayDeque<>();
private final Deque runningAsyncCalls = new ArrayDeque<>();
2.2 过程分析
Call代用enqueue方法的时候
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
方法中满足执行队列里面不足最大线程数maxRequests并且Call对应的host数目不超过maxRequestsPerHost 的时候直接把call对象直接推入到执行队列里,并启动线程任务(Call本质是一个Runnable)。否则,当前线程数过多,就把他推入到等待队列中。Call执行完肯定需要在runningAsyncCalls 队列中移除这个线程。那么readyAsyncCalls队列中的线程在什么时候才会被执行呢。
追溯下AsyncCall 线程的执行方法
@Override
protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain(forWebSocket);
if (canceled) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
这里做了核心request的动作,并把失败和回复数据的结果通过responseCallback 回调到Dispatcher。执行操作完毕了之后不管有无异常都会进入到dispactcher的finished方法。
private void finished(Deque calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
在这里call在runningAsyncCalls队列中被移除了,重新计算了目前正在执行的线程数量。并且调用了promoteCalls() 看来是来调整任务队列的
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests)
return; //
if (readyAsyncCalls.isEmpty()) return;
for (Iterator 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;
}
}
原来实在这里对readyAsyncCalls 进行调度的。最终会在readyAsyncCalls 中通过remove操作把最后一个元素取出并移除之后加入到runningAsyncCalls的执行队列中执行操作。ArrayDeque 是非线程安全的所以finished在调用promoteCalls 的时候都在synchronized块中执行的。执行等待队列线程当然的前提是runningAsyncCalls 线程数没有超上线,而且等待队列里面有等待的任务。
小结,Call在执行任务通过Dispatcher把单元任务优先推到执行队列里进行操作,如果操作完成再执行等待队列的任务。