本节将对okhttp中的关键的类和方法进行简单介绍,并梳理出执行的基本流程进行,让大家对源码有一个全局的认识。
Class Call
回顾我们上节中出现的Call对象,这个Call
是什么呢?
Call对象其实就是一个准备好执行网络请求的request,是对request进行了封装,支持取消。由于一个Call对象表示的是请求和响应流,因此同一个Call不能执行两次。
Class Dispatcher
在讲Dispatcher之前我们还是来回顾一下如何我们在执行同步或异步请求,分别是执行了Call的execute()和enqueue()方法。下面我们就来看一下这两个方法的源码。
首先,我们来看一下execute():
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
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);
}
}
其中client.dispatcher()返回就是Dispatcher对象,跟踪源码我们发现这个Dispatcher其实是client的成员变量。接下来我们再看看enqueue():
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
这里同样使用了client.dispatcher(),看到这里大家就知道了,同步和异步请求其实都是通过这个Dispatcher来完成的。那么我们就来了解一下Dispatcher是什么?
Dispatcher负责okhttp的任务调度,管理同步/异步的请求状态,并维护一个线程池,用于执行请求,是Okhttp的核心类。
Method getResponseWithInterceptorChain()
接下来我将带大家了解一下这个关键的方法,顾名思义,这个方法是用于获取请求的Response的。
回到上面同步请求execute()方法中,我们可以发现该方法内部就是通过调用这个getResponseWithInterceptorChain()来获取请求的Response。其实异步请求enqueue()方法最终也是通过调用这个方法来获取请求的Response的。这里我带大家了解一下enqueue()方法如何调用这个方法的。
回到enqueue()方法中,我们可以发现异步请求是通过client.dispatcher().enqueue(new AsyncCall(responseCallback))
来实现的。我们先看一下enqueue()方法中参数new AsyncCall(responseCallback)
的源码。
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@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) {
// Do not signal the callback twice!
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);
}
}
}
我们发现这个AsyncCall内部类其实是一个Runnable。我们再来看一下Dispatcher的enqueue()
方法的源码。
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
我们发现executorService().execute(call)
其实就是通过Dispatcher中的线程池来执行这个AsyncCall
Runnable的。这样我们再回过头来看看这个AsyncCall
的execute ()
方法,其实就是在这里调用了getResponseWithInterceptorChain()
来获取请求的Response。
讲到这里,大家是不是开始对这个getResponseWithInterceptorChain()
方法十分好奇了,这个方法是如何获取请求的Response。当然我们还是一起来看一下源码。
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(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
这段代码大家看起来可能会很奇怪,这里怎么出现这么多interceptor,大伙也没看到请求,为啥这里就直接返回了response了。其实,这里采用了责任链模式,来实现最终的请求response。具体如何实现的我会在后面的文章中给大家一一说明,这里就不展开了说。
Interceptor
Interceptor也是okhttp的核心之一,它把实际的网络重试、重定向、缓存、透明压缩、网络连接等功能拆分到独立的interceptor
中,再通过Interceptor.Chain
将这些功能环环相扣起来,最终完美实现网络请求。
我将在接下来的文章中讲述以上方法中的5个重要的拦截器interceptor
:
-
RetryAndFollowUpInterceptor
: 主要用于重试和重定向请求 -
CacheInterceptor
: 处理缓存拦截器 -
BridgeInterceptor
: 负责okhttp请求和响应对象与实际http协议中请求和响应对象之间的转换。同时处理cookies相关内容 -
ConnectionInterceptor
: 负责建立连接和流对象 -
CallServerInterceptor
: 负责完成最终的网络请求,发送请求和读取响应
基本流程图
本节最后放一张流程图,将以上几个重要的概念串联起来,便于大家从全局来认识一下okhttp。
okhttp基本流程图
在接下来的章节中,我将结合以上的基本流程图带着大家深入分析源码。
上一节 okhttp 源码学习(一)基本用法
下一节 okhttp 源码学习(三)Dispatcher 深入解析
网友评论