[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jPesRXcb-1615889568086)(https://github.com/wfeii/wfeii.github.io_raw_important/blob/master/OkHttpClient3.4/ConnectionInterceptor%E7%9A%84%E7%9B%B8%E5%85%B3%E7%B1%BB%E5%9B%BE.png?raw=true)]
主要的类包含ConnectInterceptor
,StreamAllocation
,RealConnection
,ConnectionPool
。
我们先分析ConnectionPool
,然后分析ConnectionInterceptor
。
连接池
ConnectionPool
作用主要是复用Http
连接,避免网络连接的时延,以及避免TCP调谐带来的带宽过小的问题。ConnectionPool
主要有两个方法
get
方法用于获取连接。put
方法用于添加连接。
get方法
public final class ConnectionPool {
private final Deque<RealConnection> connections = new ArrayDeque<>();
@Nullable RealConnection get(Address address, StreamAllocation streamAllocation, Route route) {
assert (Thread.holdsLock(this));
for (RealConnection connection : connections) {
if (connection.isEligible(address, route)) {
streamAllocation.acquire(connection, true);
return connection;
}
}
return null;
}
}
遍历连接池的连接,address
和route
作为参数调用RealConnection
对象的方法isEligible
来判断连接是否合适。
如果合适,就调用StreamAllocation
的acquire
方法,然后返回RealConnection
对象。当所有的连接都不合适的时候返回null
。
我们来看一下StreamAllocation
的acquire
方法。
public final class StreamAllocation {
public void acquire(RealConnection connection, boolean reportedAcquired) {
assert (Thread.holdsLock(connectionPool));
if (this.connection != null) throw new IllegalStateException();
this.connection = connection;
this.reportedAcquired = reportedAcquired;
connection.allocations.add(new StreamAllocationReference(this, callStackTrace));
}
}
先判断StreamAllocation
的变量connection
是否为null
。不为null
,说明已经包含一个连接了,直接抛出状态异常。
最重要的创建一个StreamAllocationReference
对象,StreamAllocationReference
是StreamAllocation
的弱引用。然后添加到RealConnection
对象connection
的allocations
变量中。这样就可以遍历RealConnection
的allocations
变量来查看是否被StreamAllocation
使用中。
put方法
public final class ConnectionPool {
private final Deque<RealConnection> connections = new ArrayDeque<>();
void put(RealConnection connection) {
assert (Thread.holdsLock(this));
if (!cleanupRunning) {
cleanupRunning = true;
executor.execute(cleanupRunnable);
}
connections.add(connection);
}
}
put
方法比较简单,先是判断cleanupRunning
,cleanupRunning
表示清理连接的工作正在执行。如果没有执行就调用线程池来执行cleanupRunnable
。然后是把RealConnection
对象connection
添加到变量connections
中。
连接清理
public final class ConnectionPool {
private final Runnable cleanupRunnable = new Runnable() {
@Override public void run() {
while (true) {
//通过调用cleanup方法来获取等待时间。
long waitNanos = cleanup(System.nanoTime());
//等待时间是-1直接返回
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