最近无聊看了一下OKHTTP源码,大致了解了一下我们使用OKHTTP发送网络请求之后,内部都发生了什么。简单说一下哈
我们正常发送一个get请求如下
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().get().url(url).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
@Override
public void enqueue(Callback responseCallback) {
// ......
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
client.newCall创建了一个RealCall对象,通过enqueue方法调用client.dispatcher().enqueue(new AsyncCall(responseCallback)); 将封装好的异步请求交给Dispatcher
查看Dispatcher怎么分发我们的请求
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
可以看出来,Dispatcher维护了两个队列runningAsyncCalls和readyAsyncCalls。
- 如果正在运行的队列小于maxRequests也就是64个,并且请求同一个host的数量小于maxRequestsPerHost也就是5个。那么直接将该请求加入到runningAsyncCalls队列,立刻执行。
- 如果不满足条件1,那么将该请求加入到readyAsyncCalls队列
看一下如何执行runningAsyncCalls中的请求
通过executorService().execute(call);执行该请求任务。executorService()创建了一个线程池,使用的是不存储元素的阻塞队列SynchronousQueue,也就是没有核心线程,队列不存储请求,当有请求时直接执行。
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;
}
然后我们就要看一下AsyncCall了。
- AsyncCall继承自NamedRunnable,线程池执行execute()方法时,通过NamedRunnable调用AsyncCall重写的execute方法。
- 通过getResponseWithInterceptorChain()方法获取到response之后,将response返回。
- 在finally执行 client.dispatcher().finished(this)方法,表明该请求执行完成
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
// ......
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
我们看一下一个请求执行完成以后,还有哪些操作
- RealCall在执行完成之后会在finally执行 client.dispatcher().finished(this)方法,finish方法会将当前执行过的请求从立即执行队列中移除,然后通过 promoteCalls()方法看是否有任务可以从准备执行队列添加到立即执行队列。
- 当直接运行的队列小于最大值64,并且准备执行队列中仍有请求时,遍历准备执行队列进行判断
- 判断如果加上当前请求,直接运行队列请求统一host数量仍然小于5,就把当前请求加入到直接执行队列,立刻执行,此时如果直接运行队列数量大于最大值64,那就中断循环。
- 判断如果加上当前请求,直接运行队列请求统一host数量如果大于5,就跳过当前请求。当前请求需要等下一个任务执行完成之后,再次调用promoteCalls()方法进行判断。
- 执行完判断之后,如果立即执行队列达到最大值64,那么就不再继续遍历。如果没有达到最大值64,那就接着遍历,继续判断,继续往立即执行队列中添加
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
// ...
synchronized (this) {
// 移除执行过的请求
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
// 去准备执行队列,看是否要添加请求到立即执行队列
if (promoteCalls) promoteCalls();
// ...
}
}
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
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.
}
}