特性
- OkHttp performs best when you create a single {@code OkHttpClient} instance and reuse it for all of your HTTP calls.
创建OkHttpClient的单实例作为所有http的请求会得到最好的性能表现。 - This is because each client holds its own connection pool and thread pools.
因为每个实例拥有自己的连接池和线程池 - Reusing connections and threads reduces latency and saves memory.
重用连接池和线程池以达到减少延迟和节省内存的目的。 - Conversely, creating a client for each request wastes resources on idle pools.
相反地,为每一个请求创建一个OkHttpClient实例将会导致空闲池的浪费。 - The threads and connections that are held will be released automatically if they remain idle.
线程池和连接池将会在闲置的时候将被自动释放。
本篇我们从一个网络请求的发起到收到响应数据的一个完整过程来剖析OkHttp的源码。
通常我们是这样使用的,
OkHttpClient client = new OkHttpClient();
String run(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
那么,首先我们看到OkHttpClient这个类的声明
public class OkHttpClient implements Cloneable, Call.Factory {
...
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override
public Call newCall(Request request) {
return new RealCall(this, request);
}
...
}
我们发现其实现了Call.Factory,我们可以看到Call这个接口的声明内容:
public interface Call {
/** Returns the original request that initiated this call. */
Request request();
Response execute() throws IOException;
void enqueue(Callback responseCallback);
void cancel();
boolean isExecuted();
boolean isCanceled();
interface Factory {
Call newCall(Request request);
}
}
Call对象就是发起一个请求的实体,Call.Factory顾名思义就是用来生产一个Call对象的。那么我们再看RealCall的execute究竟发生了什么,
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
// 使用Dispatcher在当前线程立即执行任务
client.dispatcher().executed(this);
// 发起请求获取响应数据
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
// 使用Dispatcher结束任务执行
client.dispatcher().finished(this);
}
}
关注到Dispatcher的执行过程
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
以及结束过程,
/** Used by {@code Call#execute} to signal completion. */
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
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();
}
}
我们再仔细的分析getResponseWithInterceptorChain()这个过程发生了什么,
private Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
RealInterceptorChain.proceed的过程如下,属于一个典型的责任链模式,
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpStream, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream,
Connection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.httpStream != null && !sameConnection(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.httpStream != 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 next = new RealInterceptorChain(
interceptors, streamAllocation, httpStream, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpStream != 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");
}
return response;
}
未完待续