OkHttp源码解析(二):深入理解

OkHttpClient

使用 OkHttp 我们首先需要创建并获得一个 OkHttpClient,OkHttpClient 是 OkHttp 中十分重要的一个类,官方推荐的使用方式是使用一个全局的 OkHttpClient 在多个类之间共享。因为每个 Client 都会有一个自己的连接池和线程池,复用 Client 可以减少资源的浪费。
它的构建采用了 Builder 模式,提供了许多可供我们配置的参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public static final class Builder {
Dispatcher dispatcher;
@Nullable
Proxy proxy;
List<Protocol> protocols;
List<ConnectionSpec> connectionSpecs;
final List<Interceptor> interceptors = new ArrayList<>();
final List<Interceptor> networkInterceptors = new ArrayList<>();
EventListener.Factory eventListenerFactory;
ProxySelector proxySelector;
CookieJar cookieJar;
@Nullable
Cache cache;
@Nullable
InternalCache internalCache;
SocketFactory socketFactory;
@Nullable
SSLSocketFactory sslSocketFactory;
@Nullable
CertificateChainCleaner certificateChainCleaner;
HostnameVerifier hostnameVerifier;
CertificatePinner certificatePinner;
Authenticator proxyAuthenticator;
Authenticator authenticator;
ConnectionPool connectionPool;
Dns dns;
boolean followSslRedirects;
boolean followRedirects;
boolean retryOnConnectionFailure;
int callTimeout;
int connectTimeout;
int readTimeout;
int writeTimeout;
int pingInterval;
}

Request

Request 所对应的就是我们 HTTP 请求中的 Request,可以对它的 url、method、header 等在 Builder 中进行配置。Request 的构建同样采用了 Builder 模式进行构建:

1
2
3
4
5
6
7
8
public static class Builder {
@Nullable
HttpUrl url;
String method;
Headers.Builder headers;
@Nullable
RequestBody body;
}

构建完 Request 后,就可以调用 OkHttpClient.newCall 方法创建对应 Call

RealCall

RealCall中有一个getResponseWithInterceptorChain方法比较重要。为什么说这个方法比较重要呢,因为无论是同步或者异步,都会执行到这个方法中,而且这个方法中用到了一个责任链模式,也是OKhttp的核心原理之一。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
//1. 用户添加的拦截器
interceptors.addAll(client.interceptors());
//2. 负责实现重定向功能
interceptors.add(retryAndFollowUpInterceptor);
//3. 将用户构造的请求转换为向服务器发送的请求,将服务器返回的响应转换为对用户友好的响应
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//4. 读取缓存、更新缓存
interceptors.add(new CacheInterceptor(client.internalCache()));
//5. 建立与服务器的连接
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
//6. 从服务器读取响应
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);
}

RealCall的由来

我们知道OKhttp中最终调用同步或者异步执行的都是Call对象,即OkHttpClient的newCall方法,但是Call只是一个接口而已,最终的实现类是RealCall,newCall方法内部是这样实现的。

1
2
3
@Override public Call newCall(Request request) {
return new RealCall(this, request);
}

所以不管同步或者异步执行的逻辑,都是在RealCall这个类中实现的,下面就去RealCall这个类中看一看。

RealCall中的同步执行流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain(false);
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}

第10行中,执行dispatcher的executed方法,也就是将当前的RealCall对象加入到同步运行队列中,然后调用到getResponseWithInterceptorChain方法获取到Response,最后在finally块中移除当前执行完毕的RealCall对象。

RealCall中的异步执行流程

1
2
3
4
5
6
7
8
9
10
11
@Override public void enqueue(Callback responseCallback) {
enqueue(responseCallback, false);
}

void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}

第10行中,执行dispatcher的enqueue方法,如果正在运行队列的数量小于64个并且相同host正在运行的数量小于5个,那么会将当前的AsyncCall对象加入到运行队列中并运行,否则加入到等待队列中等待执行。具体代码如下;

1
2
3
4
5
6
7
8
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}

那么AsyncCall是个什么鬼呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
final class AsyncCall extends NamedRunnable {
@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);
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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();
}

从上面的代码中可以看出AsyncCall就是一个Runnable,在这个线程的run方法中(execute)看到一个熟悉的方法,就是getResponseWithInterceptorChain方法。当然,异步执行需要回调的,我们也看到responseCallback的身影了,最后的finally块中,同样移除了当前的Call对象。

拦截器

接口定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
@Nullable Connection connection();
Call call();
int connectTimeoutMillis();
Chain withConnectTimeout(int timeout, TimeUnit unit);
int readTimeoutMillis();
Chain withReadTimeout(int timeout, TimeUnit unit);
int writeTimeoutMillis();
Chain withWriteTimeout(int timeout, TimeUnit unit);
}
}

执行流程

调用了 chain.request 方法获取到了本次请求的 Request 对象,之后调用了 chain.proceed 方法递归调用下一个拦截器的 interceptor 方法。最后返回了 chain.proceed 方法所返回的 Response。

1
2
3
4
5
6
7
8
9
10
11
@Override 
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// Request阶段,该拦截器在Request阶段负责做的事情

// 调用RealInterceptorChain.proceed(),其实是在递归调用下一个拦截器的intercept()方法
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);

// Response阶段,完成了该拦截器在Response阶段负责做的事情,然后返回到上一层的拦截器。
return response;
}

我们再看看是如何通过 RealInterceptorChain 将整个拦截器的调用过程连接起来的,我们先看看其构造过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
public RealInterceptorChain(List<Interceptor> interceptors, Transmitter transmitter,
@Nullable Exchange exchange, int index, Request request, Call call,
int connectTimeout, int readTimeout, int writeTimeout) {
this.interceptors = interceptors;
this.transmitter = transmitter;
this.exchange = exchange;
this.index = index;
this.request = request;
this.call = call;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
}

这里只是一些赋值过程,我们接着看到 chain.proceed 方法,看看它是如何执行的:

1
2
3
4
5
6
7
8
9
10
11
12
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException {
// ...
// 构建下一个Interceptor的Chain
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
// 获取当前Interceptor并执行intercept方法
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// ...
return response;
}

这里省略了一些异常处理,可以看到它首先构造了下一个拦截器对应的 Chain,之后获取到了当前的拦截器并调用了其 intercept 方法获取其结果,在 intercept 方法的参数中传入的就是下一个拦截器对应的 Chain,通过这种递归的设计,从而实现了从上到下,再从下到上这样一个递与归的过程,从而十分漂亮地实现了 HTTP 请求的全过程。

您的支持是我原创的动力