前面的文章分析完了 OkHttp 中的缓存机制,现在让我们继续来研究其在 ConnectInterceptor
中所进行的连接建立的相关原理。由于连接建立的过程涉及到很多在 OkHttp 中非常重要的机制,因此将分为多篇文章进行介绍,这篇文章主要是对连接建立的大体流程进行介绍。
系列索引
本系列文章基于 OkHttp3.14
OkHttp3.14 源码剖析系列(一)——请求的发起及拦截器机制概述
OkHttp3.14 源码剖析系列(二)——拦截器大体流程分析
OkHttp3.14 源码剖析系列(六)——连接复用机制及连接的建立
OkHttp3.14 源码剖析系列(七)——请求的发起及响应的读取
连接建立流程概述
在 ConnectInterceptor.intercept
方法中真正实现了连接的建立的代码如下:
// 如果请求是GET格式,需要一些额外的检查
boolean doExtensiveHealthChecks = !request.method().equals("GET");
Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks);
根据上面的代码我们可以推测,这个 Exchange
类与我们的连接是有一些关系的,真正连接的建立过程在 transmitter.newExchange
中实现。
我们看到 transmitter.newExchange
方法:
/**
* Returns a new exchange to carry a new request and response.
*/
Exchange newExchange(Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
synchronized (connectionPool) {
if (noMoreExchanges) {
throw new IllegalStateException("released");
}
if (exchange != null) {
throw new IllegalStateException("cannot make a new request because the previous response "
+ "is still open: please call response.close()");
}
}
// 寻找ExchangeCodec对象
ExchangeCodec codec = exchangeFinder.find(client, chain, doExtensiveHealthChecks);
// 通过找到的codec对象构建Exchange对象
Exchange result = new Exchange(this, call, eventListener, exchangeFinder, codec);
// 进行一些变量的赋值
synchronized (connectionPool) {
this.exchange = result;
this.exchangeRequestDone = false;
this.exchangeResponseDone = false;
return result;
}
}
获取连接
上面首先通过 exchangeFinder.find
方法进行了对 ExchangeCodec
的查找,找到对应的 ExchangeCodec
对象,之后通过这个 codec 对象构建了一个 Exchange
对象并返回
那么什么是 ExchangeCodec
对象呢?我们先看到 exchangeFinder.find
方法:
public ExchangeCodec find(
OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
int connectTimeout = chain.connectTimeoutMillis();
int readTimeout = chain.readTimeoutMillis();
int writeTimeout = chain.writeTimeoutMillis();
int pingIntervalMillis = client.pingIntervalMillis();
boolean connectionRetryEnabled = client.retryOnConnectionFailure();
try {
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
return resultConnection.newCodec(client, chain);
} catch (RouteException e)