这篇文章主要梳理一下 OkHttp 的请求流程,对 OkHttp 的实现原理有个总体的把握,再深刻细节的实现会更加容易。html
建议将 OkHttp 的源码下载下来,使用 IDEA 编辑器能够直接打开阅读。我这边也将最新版的源码下载下来,进行了注释,有须要的能够直接从 这里 下载查看。java
咱们先看一下 OkHttp 的基本使用。android
// 一、建立 Request
Request request = new Request.Builder()
.get()
.url("xxx")
.build();
// 二、建立 OKHttpClient
OkHttpClient client = new OkHttpClient();
// 三、建立 Call
Call call = client.newCall(request);
try {
// 四、同步请求
Response response = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
// 五、异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
复制代码
上面的代码中,首先构建一个请求 Request 和一个客户端 OkHttpClient,而后 OkHttpClient 对象根据 request 调用 newCall
方法建立 Call 对象,再调用 execute
或者 enqueue
方法进行同步或者异步请求。git
接下来咱们看一看关键类和关键流程的具体实现。github
Request 类封装了一次请求须要传递给服务端的参数:请求 method 如 GET/POST 等、一些 header、RequestBody 等等。web
Request 类未对外提供 public 的构造函数,因此构建一个 Request 实例须要使用构造者模式构建。缓存
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tags = Util.immutableMap(builder.tags);
}
复制代码
OkHttpClient 支持两种构造方式。安全
一种是默认的构造方式:bash
OkHttpClient client = new OkHttpClient();
复制代码
看一下构造函数:服务器
public OkHttpClient() {
this(new Builder());
}
复制代码
这里 OkHttpClient 内部默认配置了一些参数。
OkHttpClient(Builder builder) {...}
复制代码
另外一种是经过 Builder 配置参数,最后经过 build
方法构建一个 OkHttpClient 对象。
OkHttpClient client = new OkHttpClient.Builder().build();
public OkHttpClient build() {
return new OkHttpClient(this); // 这里的 this 是 Builder 实例
}
复制代码
咱们看一下 OkHttpClient 可配置哪些参数:
final Dispatcher dispatcher; // 调度器
final @Nullable
Proxy proxy; // 代理
final List<Protocol> protocols; // 协议
final List<ConnectionSpec> connectionSpecs; // 传输层版本和链接协议
final List<Interceptor> interceptors; // 拦截器
final List<Interceptor> networkInterceptors; // 网络拦截器
final EventListener.Factory eventListenerFactory;
final ProxySelector proxySelector; // 代理选择器
final CookieJar cookieJar; // cookie
final @Nullable
Cache cache; // 缓存
final @Nullable
InternalCache internalCache; // 内部缓存
final SocketFactory socketFactory; // socket 工厂
final SSLSocketFactory sslSocketFactory; // 安全套接层 socket 工厂,用于 https
final CertificateChainCleaner certificateChainCleaner; // 验证确认响应证书 适用 HTTPS 请求链接的主机名
final HostnameVerifier hostnameVerifier; // 主机名字验证
final CertificatePinner certificatePinner; // 证书链
final Authenticator proxyAuthenticator; // 代理身份验证
final Authenticator authenticator; // 本地身份验证
final ConnectionPool connectionPool; // 链接池
final Dns dns; // 域名
final boolean followSslRedirects; // 安全套接层重定向
final boolean followRedirects; // 本地重定向
final boolean retryOnConnectionFailure; // 重试链接失败
final int callTimeout;
final int connectTimeout;
final int readTimeout;
final int writeTimeout;
final int pingInterval;
复制代码
Call 是一个接口,是请求的抽象描述,具体实现类是 RealCall,经过Call.Factory 建立。
public interface Call extends Cloneable {
// 返回当前请求
Request request();
// 同步请求方法
Response execute() throws IOException;
// 异步请求方法
void enqueue(Callback responseCallback);
// 取消请求
void cancel();
// 请求是否在执行(当execute()或者enqueue(Callback responseCallback)执行后该方法返回true)
boolean isExecuted();
// 请求是否被取消
boolean isCanceled();
Timeout timeout();
// 建立一个新的如出一辙的请求
Call clone();
interface Factory {
Call newCall(Request request);
}
}
复制代码
OkHttpClient 实现了 Call.Factory,负责根据 Request 建立新的 Call:
Call call = client.newCall(request);
复制代码
看一下 newCall
方法。
@Override
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
复制代码
这里咱们发现实际上调用了 RealCall 的静态方法 newRealCall
, 不难猜想 这个方法就是建立 Call 对象。
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
复制代码
从上面的分析咱们知道,同步请求调用的实际是 RealCall 的 execute
方法。
@Override public Response execute() throws IOException {
synchronized (this) {
// 每一个 call 只能执行一次
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
timeout.enter();
eventListener.callStart(this);
try {
// 请求开始, 将本身加入到runningSyncCalls队列中
client.dispatcher().executed(this);
// 经过一系列拦截器请求处理和响应处理获得最终的返回结果
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
e = timeoutExit(e);
eventListener.callFailed(this, e);
throw e;
} finally {
// 请求完成, 将其从runningSyncCalls队列中移除
client.dispatcher().finished(this);
}
}
复制代码
这里主要作了这几件事:
getResponseWithInterceptorChain()
函数获取 HTTP 返回结果。dispatcher
本身已经执行完毕,将 call 从 runningSyncCalls 队列中移除。这里涉及到了 Dispatcher 这个类,咱们在异步请求这一节中再介绍。
真正发出网络请求以及解析返回结果的是在 getResponseWithInterceptorChain
方法中进行的。
Response getResponseWithInterceptorChain() throws IOException {
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);
复制代码
getResponseWithInterceptorChain
方法的代码量并很少,可是却完成了全部的请求处理过程。
这里先是建立了一个 Interceptor 的集合,而后将各种 interceptor 所有加入到集合中,包含如下 interceptor:
添加完拦截器后,建立了一个 RealInterceptorChain 对象,将集合 interceptors 和 index(数值0)传入。接着调用其 proceed
方法进行请求的处理,咱们来看 proceed
方法。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
...
// 建立下一个RealInterceptorChain,将index+1(下一个拦截器索引)传入
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
// 获取当前的拦截器
Interceptor interceptor = interceptors.get(index);
// 经过Interceptor的intercept方法进行处理
Response response = interceptor.intercept(next);
...
return response;
}
复制代码
咱们来看一些关键代码:
RealInterceptorChain 的 proceed
方法先建立 RealInterceptorChain 的对象,将集合 interceptors 和 index + 1 传入。从前面的分析知道,初始 index 为 0。
而后获取当前 index 位置上的 Interceptor,将建立的 RealInterceptorChain 对象 next 传入到当前拦截器的 intercept
方法中,intercept
方法内部会调用 next 的 proceed 方法,一直递归下去,最终完成一次网络请求。
因此每一个 Interceptor 主要作两件事情:
异步请求调用的是 RealCall 的 enqueue
方法。
public void enqueue(Callback responseCallback) {
synchronized(this) {
if (this.executed) {
throw new IllegalStateException("Already Executed");
}
this.executed = true;
}
this.captureCallStackTrace();
this.eventListener.callStart(this);
this.client.dispatcher().enqueue(new RealCall.AsyncCall(responseCallback));
}
复制代码
与同步请求同样,异步请求也涉及了一个重要的参与者 Dispatcher,它的做用是:控制每个 Call 的执行顺序和生命周期。它内部维护了三个队列:
对于同步请求,因为它是即时运行的, Dispatcher 只须要运行前请求前存储到 runningSyncCalls,请求结束后从 runningSyncCalls 中移除便可。
对于异步请求,Dispatcher 是经过启动 ExcuteService 执行,线程池的最大并发量 64,异步请求先放置在 readyAsyncCalls,能够执行时放到 runningAsyncCalls 中,执行结束从runningAsyncCalls 中移除。
咱们看一下具体实现细节,下面是 Dispatcher 的 enqueue
方法,先将 AsyncCall 添加到 readyAsyncCalls。
void enqueue(AsyncCall call) {
// 将AsyncCall加入到准备异步调用的队列中
synchronized (this) {
readyAsyncCalls.add(call);
}
promoteAndExecute();
}
复制代码
再看 promoteAndExecute
方法:
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
复制代码
这里主要的工做有:
executableCalls
列表中。executableCalls
取出请求 AsyncCall 对象,调用其 executeOn
方法。void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
eventListener.callFailed(RealCall.this, ioException);
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
client.dispatcher().finished(this); // This call is no longer running!
}
}
}
复制代码
能够看到 executeOn
方法的参数传递的是 ExecutorService 线程池对象,方法中调用了线程池的 execute
方法,因此 AsyncCall 应该是实现了 Runnable 接口,咱们看看它的 run
方法是怎样的。
AsyncCall 继承自 NamedRunnable 抽象类。
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();
}
复制代码
因此当线程池执行 execute
方法会走到 NamedRunnable 的 run
方法,run
方法中又调用了 抽象方法 execute
,咱们直接看 AsyncCall 的 execute
方法。
@Override
protected void execute() {
boolean signalledCallback = false;
timeout.enter();
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) {
e = timeoutExit(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);
}
}
}
复制代码
这里咱们又看到了熟悉的 getResponseWithInterceptorChain
方法。
这样看来,同步请求和异步请求的原理是同样的,都是在 getResponseWithInterceptorChain()
函数中经过 Interceptor 链条来实现的网络请求逻辑。
以上即是 Okhttp 整个请求与响应的具体流程,OkHttp 流程图以下。
简述 OkHttp 的请求流程:
getResponseWithInterceptorChain
方法实现。getResponseWithInterceptorChain
方法中采用了责任链模式,每个拦截器各司其职,主要作两件事。