这个方法是在连接是返回stream对象的。我们看这个方法里的这段代码。
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);
//省略其他代码
findHealthyConnection方法返回健康的链接。我们继续跟踪代码。最后到了findConnection方法。
//省略其他代码
RealConnection pooledConnection = Internal.instance.get(connectionPool, address, this);
//省略其他代码
上面的Internal.instance是啥玩意呢?这个是在OkHttpCLient的静态代码块中初始化的。我们看下他对应的get方法。
@Override public RealConnection get(
ConnectionPool pool, Address address, StreamAllocation streamAllocation) {
return pool.get(address, streamAllocation);
}
这里调用ConnectionPool的get方法返回一个RealConnection对象。
RealConnection get(Address address, StreamAllocation streamAllocation) {
assert (Thread.holdsLock(this));
for (RealConnection connection : connections) {
if (connection.allocations.size() < connection.allocationLimit
&& address.equals(connection.route().address)
&& !connection.noNewStreams) {
streamAllocation.acquire(connection);
return connection;
}
}
return null;
}
这样就返回了一个已经存在的同样的RealConnect对象。
streamAllocation.acquire(connection);是RealConnection的allocations增加了一个弱引用。
回到StreamAllocation的findConnection方法,,如果从连接池中拿到了RealConnection对象,就返回。否则,继续。生成一个RealConnection对象,并加入连接池。
现在我们看看健康检查是怎么回事。
public boolean isHealthy(boolean doExtensiveChecks) {
if (socket.isClosed() || socket.isInputShutdown() || socket.isOutputShutdown()) {
return false;
}
if (framedConnection != null) {
return true; // TODO: check framedConnection.shutdown.
}
if (doExtensiveChecks) {
try {
int readTimeout = socket.getSoTimeout();
try {
socket.setSoTimeout(1);
if (source.exhausted()) {
return false; // Stream is exhausted; socket is closed.
}
return true;
} finally {
socket.setSoTimeout(readTimeout);
}
} catch (SocketTimeoutException ignored) {
// Read timed out; socket is good.
} catch (IOException e) {
return false; // Couldn't read; socket is closed.
}
}
return true;
}
这里就是检查socket的各项指标是够正确,比如说socket关闭没,输入输出通道关闭没。
如果不健康的话就调用noNewStream,这里就是释放这个RealConnection所占的资源,并且从上面操作,直到返回一个可用的健康的RealConnection。加入池里没有,就创建一个新的。并将这个新的加入池中,相关代码如下。
RealConnection newConnection = new RealConnection(selectedRoute);
acquire(newConnection);
synchronized (connectionPool) {
Internal.instance.put(connectionPool, newConnection);
this.connection = newConnection;
if (canceled) throw new IOException("Canceled");
}
public ConnectionPool() {
this(5, 5, TimeUnit.MINUTES);
}
恩,默认是5个链接,每个链接的存活时长为5分钟。链接池在加入第一个链接对象的时候,会启动cleanupRunnable,做清理。我们看下这个。
private final Runnable cleanupRunnable = new Runnable() {
@Override public void run() {
while (true) {
long waitNanos = cleanup(System.nanoTime());
if (waitNanos == -1) return;
if (waitNanos > 0) {
long waitMillis = waitNanos / 1000000L;
waitNanos -= (waitMillis * 1000000L);
synchronized (ConnectionPool.this) {
try {
ConnectionPool.this.wait(waitMillis, (int) waitNanos);
} catch (InterruptedException ignored) {
}
}
}
}
}
};
在cleanup函数中,会根据一定的策略移除链接。其中还有很多细节,我在这里就不关注了,感兴趣的同学自己去看下他的策略吧。