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
35public static final class Builder {
Dispatcher dispatcher;
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;
Cache cache;
InternalCache internalCache;
SocketFactory socketFactory;
SSLSocketFactory sslSocketFactory;
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
8public static class Builder {
HttpUrl url;
String method;
Headers.Builder headers;
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
25Response 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
3public Call newCall(Request request) {
return new RealCall(this, request);
}
所以不管同步或者异步执行的逻辑,都是在RealCall这个类中实现的,下面就去RealCall这个类中看一看。
RealCall中的同步执行流程
1 | public Response execute() throws IOException { |
第10行中,执行dispatcher的executed方法,也就是将当前的RealCall对象加入到同步运行队列中,然后调用到getResponseWithInterceptorChain方法获取到Response,最后在finally块中移除当前执行完毕的RealCall对象。
RealCall中的异步执行流程
1 | public void enqueue(Callback responseCallback) { |
第10行中,执行dispatcher的enqueue方法,如果正在运行队列的数量小于64个并且相同host正在运行的数量小于5个,那么会将当前的AsyncCall对象加入到运行队列中并运行,否则加入到等待队列中等待执行。具体代码如下;
1 | synchronized void enqueue(AsyncCall 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
24final class AsyncCall extends NamedRunnable {
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 | public abstract class NamedRunnable implements Runnable { |
从上面的代码中可以看出AsyncCall就是一个Runnable,在这个线程的run方法中(execute)看到一个熟悉的方法,就是getResponseWithInterceptorChain方法。当然,异步执行需要回调的,我们也看到responseCallback的身影了,最后的finally块中,同样移除了当前的Call对象。
拦截器
接口定义
1 | public interface Interceptor { |
执行流程
调用了 chain.request 方法获取到了本次请求的 Request 对象,之后调用了 chain.proceed 方法递归调用下一个拦截器的 interceptor 方法。最后返回了 chain.proceed 方法所返回的 Response。1
2
3
4
5
6
7
8
9
10
11
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
13public 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
12public 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 请求的全过程。