ConnectInterceptor
与服务端建立连接,并且获得通向服务端的输入和输出流对象
- 创建输入输出流
- 建立连接
- 执行下一个拦截器
ConnectInterceptor部分源码
@Override
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
boolean doExtensiveHealthChecks = !request.method().equals("GET");
//创建输出流
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
//获取连接
RealConnection connection = streamAllocation.connection();
//执行下一个拦截器
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
StreamAllocation.newStream()
newStream()方法主要做了如下的工作
-
- 从缓冲池ConnectionPool获取一个RealConnection对象,如果缓冲池里面没有就创建一个RealConnection对象并且放入缓冲池中,具体的说是放入ConnectionPool的ArrayDeque队列中
-
- 获取RealConnection对象后并调用其connect打开Socket链接
public HttpCodec newStream(
OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
...
try {
//获取一个RealConnection对象(在连接池中寻找或者在新创建一个连接)
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
//获取HttpCodec 对象
HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);
//返回HttpCodec对象
synchronized (connectionPool) {
codec = resultCodec;
return resultCodec;
}
} catch (IOException e) {
throw new RouteException(e);
}
}
1、调用findHealthyConnection获取一个RealConnection对象
2、通过获取到的RealConnection来生成一个HttpCodec对象并返回
StreamAllocation. findHealthyConnection()
private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
int writeTimeout, int pingIntervalMillis, boolean connectionRetryEnabled,
boolean doExtensiveHealthChecks) throws IOException {
while (true) {
//获取RealConnection对象
RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
pingIntervalMillis, connectionRetryEnabled);
//如果这个连接是新的连接,那么不需要进行可用新检查了,直接返回这个新的的连接
synchronized (connectionPool) {
if (candidate.successCount == 0) {
return candidate;
}
}
//这个连接是从连接池中取出的,检测是否可用
if (!candidate.isHealthy(doExtensiveHealthChecks)) {
//不可用关闭这个连接,从新寻找
noNewStreams();
continue;
}
return candidate;
}
}
1、开启一个while循环,调用findConnection继续获取RealConnection对象candidate 。
2、如果candidate 的successCount 为0,直接返回之,while循环结束
3、如果candidate是一个不“健康”的对象,则对此对象进行调用noNewStreams进行销毁处理,继续循环调用findConnection获取RealConnection对象。
(注:不健康的RealConnection条件为如下几种情况: RealConnection对象 socket没有关闭 ,socket的输入流没有关闭 ,socket的输出流没有关闭 ,http2时连接没有关闭 )
StreamAllocation. findConnection()
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) {
if (released) throw new IllegalStateException("released");
if (codec != null) throw new IllegalStateException("codec != null");
if (canceled) throw new IOException("Canceled");
releasedConnection = this.connection;
//释放不可复用的connection
toClose = releaseIfNoNewStreams();
if (this.connection != null) {
//尝试复用
result = this.connection;
releasedConnection = null;
}
if (!reportedAcquired) {
releasedConnection = null;
}
if (result == null) {
Internal.instance.get(connectionPool, address, this, 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) {
//可以复用直接返回
return result;
}
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) {
List 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;
//初始化
result = new RealConnection(connectionPool, selectedRoute);
//将当前StreamAllocation的弱引用
//交给result的allocations集合里
//并将result赋值给this.connection这个引用
acquire(result, false);
}
}
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result);
return result;
}
//开始Socket连接,为阻塞操作
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
connectionRetryEnabled, call, eventListener);
routeDatabase().connected(result.route());
Socket socket = null;
synchronized (connectionPool) {
reportedAcquired = true;
//将新创建的RealConection放入到缓冲池
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;
}
结合代码中的注释,这个类大体上做了如下几个工作:
1、StreamAllocation的connection能复用就复用之
2、如果connection不能复用,则从连接池中获取RealConnection,获取成功则返回
3,如果连接池里没有则new一个RealConnection对象,并放入连接池中
4.最终调用RealConnection的connect方法打开一个socket链接