这个拦截器的职责很简单,就是获取一份和服务器的连接,具体来说就是一个socket,然后执行下一个拦截器。
他的功能主要是StreamAllocation这个类完成的,StreamAllocation是在第一个拦截器:重定向拦截器创建的。
public HttpCodec newStream(
OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
....
try {
//找到一个健康的连接
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, pingIntervalMillis, connectionRetryEnabled,
doExtensiveHealthChecks);
//利用连接实例化流HttpCodec对象,如果是HTTP/2返回Http2Codec,否则返回Http1Codec
HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);
synchronized (connectionPool) {
codec = resultCodec;
return resultCodec;
}
} catch (IOException e) {
throw new RouteException(e);
}
}
private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
int writeTimeout, int pingIntervalMillis,
boolean connectionRetryEnabled,
boolean doExtensiveHealthChecks) throws IOException {
while (true) {
//找到一个连接
RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
pingIntervalMillis, connectionRetryEnabled);
//如果这个连接是新建立的,那肯定是健康的,直接返回
synchronized (connectionPool) {
if (candidate.successCount == 0) {
return candidate;
}
}
//如果不是新创建的,需要检查是否健康
if (!candidate.isHealthy(doExtensiveHealthChecks)) {
// 不健康 关闭连接,释放Socket,从连接池移除
// 继续下次寻找连接操作
noNewStreams();
continue;
}
return candidate;
}
}
这里是真正的去找一个连接的过程,分为四步,第一,先判断上一次的connection是否仍然存在,存在直接返回了;第二,如果不在了,那么从连接池找,如果找到了,就返回这个连接;第三,还是没找到,就遍历所有的路由,再从连接池找一次;第四,最终还没找到,就创建一个新的连接,并建立socket连接
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
boolean foundPooledConnection = false;
RealConnection result = null;
Route selectedRoute = null;
Connection releasedConnection;
Socket toClose;
synchronized (connectionPool) {
.....
releasedConnection = this.connection;
toClose = releaseIfNoNewStreams();
//this.connection就是上一次使用连接时保存的那个connection,在acquire(新建连接)
//方法中会被赋值,在deallocate方法中会被置空,如果他不为null,就赋值给result
if (this.connection != null) {
// We had an already-allocated connection and it's good.
result = this.connection;
releasedConnection = null;
}
if (!reportedAcquired) {
// If the connection was never reported acquired, don't report it as released!
releasedConnection = null;
}
//如果上一次的连接为空了,尝试去连接池获取
if (result == null) {
//尝试从连接池获取连接,如果有可复用的连接,会给第三个参数 this的connection赋值
Internal.instance.get(connectionPool, address, this, null);
//connection != null 说明从连接池找到了连接,否则没找到
if (connection != null) {
foundPooledConnection = true;
result = connection;
} else {
selectedRoute = route;
}
}
}
closeQuietly(toClose);
if (releasedConnection != null) {
eventListener.connectionReleased(call, releasedConnection);
}
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result);
}
//经过上边的两步,有连接了就直接返回
if (result != null) {
// If we found an already-allocated or pooled connection, we're done.
return result;
}
// If we need a route selection, make one. This is a blocking operation.
//创建一个路由 (dns解析的所有ip与代理的组合)
boolean newRouteSelection = false;
if (selectedRoute == null && (routeSelection == null || !routeSelection.hasNext())) {
newRouteSelection = true;
routeSelection = routeSelector.next();
}
//走到这里说明还是没有找到连接,这个时候遍历所有路由,再去连接池找一次
synchronized (connectionPool) {
if (canceled) throw new IOException("Canceled");
if (newRouteSelection) {
// Now that we have a set of IP addresses, make another attempt at getting a
// connection from
// the pool. This could match due to connection coalescing.
//根据代理和不同的ip从连接池中找可复用的连接
List<Route> routes = routeSelection.getAll();
for (int i = 0, size = routes.size(); i < size; i++) {
Route route = routes.get(i);
Internal.instance.get(connectionPool, address, this, route);
if (connection != null) {
foundPooledConnection = true;
result = connection;
this.route = route;
break;
}
}
}
//还是没找到,必须新建一个连接了
if (!foundPooledConnection) {
if (selectedRoute == null) {
selectedRoute = routeSelection.next();
}
route = selectedRoute;
refusedStreamCount = 0;
//new出来一个连接
result = new RealConnection(connectionPool, selectedRoute);
acquire(result, false);
}
}
// If we found a pooled connection on the 2nd time around, we're done.
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result);
return result;
}
// Do TCP + TLS handshakes. This is a blocking operation.
// 实际上就是创建socket连接,但是要注意的是如果存在http代理的情况
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
connectionRetryEnabled, call, eventListener);
routeDatabase().connected(result.route());
Socket socket = null;
synchronized (connectionPool) {
reportedAcquired = true;
//将新创建的连接放到连接池中
Internal.instance.put(connectionPool, result);
if (result.isMultiplexed()) {
socket = Internal.instance.deduplicate(connectionPool, address, this);
result = connection;
}
}
closeQuietly(socket);
eventListener.connectionAcquired(call, result);
return result;
}
获取到连接之后就根据相应的协议,创建一个Http1Codec或者Http2Codec,然后执行下一个拦截器。
网友评论