OkHttp使用过程中基本上分为三步:
//1.创建一个OkHttpClient对象
OkHttpClient client = new OkHttpClient();
//2.创建一个请求
Request request = new Request.Builder()
.url(url)
.get().build();
//3.先把Request封装成一个Call对象,然后执行请求
Response response = client.newCall(request).execute();
下面就根据这三步来看看源码,了解一下思路。具体细节就不去细看了:
1.创建一个OkHttpClient对象
//调度器。主要作用是通过双端队列保存Calls(同步&异步Call),同时在线程池中执行异步请求
final Dispatcher dispatcher;
//应用拦截器的List
final List<Interceptor> interceptors;
// 网络拦截器的List
final List<Interceptor> networkInterceptors;
//使用Builder模式构造一个OkHttpClient实例
public OkHttpClient() {
this(new Builder());
}
其实在构造过程中没啥好看的,就是使用Builder模式构造一个实例呗,只是会默认设置一下里面的变量。
这些变量中最重要的就是那三个,已经标出来了。
2.构造一个Request
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
final Map<Class<?>, Object> tags;
}
其实这个类没啥好说的,主要就是里面的一些变量。比如请求的Url,请求方法 method, 请求头 headers, 请求体body等。
相应的,有Request 那就必须得有 Response , 也没啥,里面也有一些变量,大致上都差不多,具体细节不用追究。
3.构造一个Call对象
也就是调用了 OkHttpClient#newCall 方法:
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
好吧,看看 RealCall#newRealCall 方法:
/**
* 将网络请求Request封装成一个RealCall对象
*/
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
好吧,就是创建一个RealCall对象而已。
好像到现在都没看到啥实质内容啊。
接下来才是重点。
4.1 对于同步,执行execute 方法
也就是执行RealCall#execute 方法:
/**
* 同步请求执行
*/
@Override public Response execute() throws IOException {
//executed如果是true,就说明已经被执行过了。在此调用就会抛出错误。一个Call只能被调用一次
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//追踪栈信息,不用管
captureCallStackTrace();
eventListener.callStart(this);
//最关键的部分,将请求交给 Dispatcher 去处理。
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().executed(this);
Response result = getResponseWithInterceptorChain();
首先看看第一句,这个client.dispatcher()其实返回的就是一个 Dispatcher 对象,该类中主要有以下几个重要的变量:
//线程池(核心线程为0,非核心线程为无限)
private @Nullable ExecutorService executorService;
//异步请求的双向队列。当单个Host并发超过5个后,Call对象就放入该队列中。
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//异步请求的双向队列,当前正在执行的Call
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//同步请求放入该双向队列中
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
而execute 方法就这么一句话:
/**
* 执行同步请求。直接把Call添加到正在执行请求的双向队列中
*/
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
所以实在没看出啥来。
好吧,接下来我们看看第二句:
Response result = getResponseWithInterceptorChain();
看看这个方法:
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));
//创建一个拦截器链类。RealInterceptorChain是实现了Interceptor.Chain接口的类
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//把Chain 传递到下一个拦截器中
return chain.proceed(originalRequest);
}
这个方法就是添加各种拦截器,然后执行拦截器的 proceed 方法。那就看看 RealInterceptorChain#proceed 方法:
/**
* 执行拦截器链类该方法,获取到Response对象
*/
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//这里说明拦截器已经没了,拦截器的数量就是interceptors.size()。
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
//又新建了一个 RealInterceptorChain。可以看到了index+1,实际上这个就是用来控制遍历interceptors列表的。
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
//顺序调用拦截器链中的每个拦截器,然后执行intercept方法(自定义拦截器的时候需要重写该拦截器)
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;
}
可以看到,其核心思想就是去遍历 interceptors(一个List)的所有元素,然后调用每个拦截器的 intercept 方法,可以看到传入的参数是下一个拦截器的Chain.
这里有点疑问?为啥调用了intercept 方法就可以遍历整个interceptors列表呢?
这是因为每个拦截器的 intercept 方法内部都都有这么一句(最后一个拦截器除外):
chain.proceed(request)
这就是一个循环调用,循环的终止条件就是index >= interceptors.size()。
总结:
对于同步请求,主要步骤如下:
- 调用 RealCall#execute 方法。
- 调用 Dispatcher#executed 方法,作用就是将call 加入的 runningAsyncCalls队列中
- 调用 RealCall#getResponseWithInterceptorChain,用于设置各种拦截器,然后并执行拦截器的 intercept 方法,并返回一个Response对象
- 调用 Dispatcher#finished 方法,传入的第三个参数为false, 即不执行 promoteCalls方法,到此结束。
对于拦截器的链式调用如下:
- 执行 RealCall#getResponseWithInterceptorChain 方法,创建一个拦截器的列表interceptors,然后创建一个Chain, 执行Chian#proceed方法
- 在 RealInterceptorChain#proceed 方法中,在创建一个Chain, 然后根据索引取出interceptors里面的一个拦截器,调用 Interceptor#intercept 方法,并把新建作为参数传入到拦截器里
- Interceptor#intercept 方法里,执行完各自的需求的额步骤后,在调用Chian#proceed方法,最后一个拦截器不需要执行。
4.2 对于异步的,调用enqueue方法
也就是直接调用了 RealCall#enqueue 方法。
/**
* 异步执行请求
*/
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//用来追踪栈的信息,不用管,不影响。
captureCallStackTrace();
eventListener.callStart(this);
//AsyncCall 实际上就是一个Runable的实现类
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
好吧,直接转到了Dispatcher#enqueue 方法,
/**
* 执行异步请求
*/
synchronized void enqueue(AsyncCall call) {
//判断当前正在执行的请求总数是否小于64,并且单个Host正在执行的请求小于5
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//满足条件,放入runningAsyncCalls,并使用线程池执行该Call
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
//不满足条件,放入readyAsyncCalls中
readyAsyncCalls.add(call);
}
}
可以看到,如果当前可以执行,就放入到runningAsyncCalls,然后通过线程池执行该请求。不能够立即执行的,就放入等待队列中(即readyAsyncCalls)。
对于 executorService().execute(call),这个call 实际上市RealCall的内部类AsyncCall,这个AsyncCall实际上是一个间接实现了Runnable的类,所以直接看 AsyncCall#execute方法:
@Override protected void execute() {
boolean signalledCallback = false;
try {
//拦截器链
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
//重试失败,调用onFailure方法抛出错误
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 {
//结束,调用Dispatcher#finished 方法
client.dispatcher().finished(this);
}
}
}
可以看到,getResponseWithInterceptorChain 方法,之前同步的时候已经说过了。所以已经知道了怎么执行异步请求了。
还有一点finally 代码快中执行了Dispatcher#finished 方法,去看看:
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
//上一个请求执行完成后,调用 promoteCalls 来循环执行下一个请求
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
/**
* 遍历正在等待执行的Call(即readyAsyncCalls双向队列中的Call)
*/
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();
//同一个Host的请求不足5个,满足条件
if (runningCallsForHost(call) < maxRequestsPerHost) {
//将Call对象从readyAsyncCalls队列中移除并添加到runningAsyncCalls,然后执行该Call
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
//遍历过程中,只要 runningAsyncCalls 达到了了最大值,就停止
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
ok, 可以看到了,基本思想就是把readyAsyncCalls的元素拿到runningAsyncCalls并放在线程池中执行。
对于异步的总结如下:
- 执行 RealCall#enqueue 方法
- 执行 Dispatcher#enqueue 方法。如果当前runningAsyncCalls队列可以放入元素,就直接add,然后调用线程池执行ExecutorService().execute(call)。否则就放入readyAsyncCalls队列中,等待执行.
- 在线程池中的call,实际上是间接实现了Runnable接口的AsyncCall类,执行execute 方法。
- AsyncCall#execute 中,先调用getResponseWithInterceptorChain返回Response对象,这里一个call就执行完成了。最后调用 Dispatcher#finished方法。
- 在Dispatcher#finished调用了 Dispatcher#promoteCalls方法,该方法就是将 call 从 readyAsyncCalls 中取出放到 runningAsyncCalls 中并使用线程池执行该call。