- 首先简单介绍okhttp是一个Http请求的库,以下引用官方文档的介绍:
OkHttp is an HTTP client that’s efficient by default:
- HTTP/2 support allows all requests to the same host to share a socket.
- Connection pooling reduces request latency (if HTTP/2 isn’t available).
- Transparent GZIP shrinks download sizes.
- Response caching avoids the network completely for repeat requests..
- 连接池切入点分析: 2.1 okhttp3.ConnectionPool :主要充当维护连接管理者,底层实现是依附于okhttp3.internal.connection.RealConnectionPool。
/**
* Manages reuse of HTTP and HTTP/2 connections for reduced network latency. HTTP requests that
* share the same {@link Address} may share a {@link Connection}. This class implements the policy
* of which connections to keep open for future use.
*/
public final class ConnectionPool {
final RealConnectionPool delegate;
/**
* Create a new connection pool with tuning parameters appropriate for a single-user application.
* The tuning parameters in this pool are subject to change in future OkHttp releases. Currently
* this pool holds up to 5 idle connections which will be evicted after 5 minutes of inactivity.
*/
public ConnectionPool() {
this(5, 5, TimeUnit.MINUTES);
}
public ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
this.delegate = new RealConnectionPool(maxIdleConnections, keepAliveDuration, timeUnit);
}
/** Returns the number of idle connections in the pool. */
public int idleConnectionCount() {
return delegate.idleConnectionCount();
}
/** Returns total number of connections in the pool. */
public int connectionCount() {
return delegate.connectionCount();
}
/** Close and remove all idle connections in the pool. */
public void evictAll() {
delegate.evictAll();
}
}
2.2 RealConnectionPool:是真正管理维护连接的类,其中连接回收关键的方法:okhttp3.internal.connection.RealConnectionPool#cleanup 以及okhttp3.internal.connection.RealConnectionPool#pruneAndGetAllocationCount
2.3 cleanup: 由okhttp3.internal.connection.RealConnectionPool#cleanupRunnable触发调用,遍历连接列表,尝试找到当前最长空闲时长的连接以及其对应时长,判断是否可以被回收。
/**
* Performs maintenance on this pool, evicting the connection that has been idle the longest if
* either it has exceeded the keep alive limit or the idle connections limit.
*
* <p>Returns the duration in nanos to sleep until the next scheduled call to this method. Returns
* -1 if no further cleanups are required.
*/
long cleanup(long now) {
int inUseConnectionCount = 0;
int idleConnectionCount = 0;//统计空闲连接数量
RealConnection longestIdleConnection = null;
long longestIdleDurationNs = Long.MIN_VALUE;
// Find either a connection to evict, or the time that the next eviction is due.
synchronized (this) {
// 遍历查找最长空闲时间的连接以及该连接对应时长
for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) {
RealConnection connection = i.next();
// If the connection is in use, keep searching.
if (pruneAndGetAllocationCount(connection, now) > 0) {
inUseConnectionCount++;
continue;
}
idleConnectionCount++;
// If the connection is ready to be evicted, we're done.
long idleDurationNs = now - connection.idleAtNanos;
if (idleDurationNs > longestIdleDurationNs) {
longestIdleDurationNs = idleDurationNs;
longestIdleConnection = connection;
}
}
if (longestIdleDurationNs >= this.keepAliveDurationNs
|| idleConnectionCount > this.maxIdleConnections) {
// We've found a connection to evict. Remove it from the list, then close it below (outside
// of the synchronized block).
// 满足最大空闲连接个数>配置个数或者最长空闲时间的连接其空间时间超过存活配置时间,触发回收
connections.remove(longestIdleConnection);
} else if (idleConnectionCount > 0) {
// A connection will be ready to evict soon.
// 返回连接的到期时间
return keepAliveDurationNs - longestIdleDurationNs;
} else if (inUseConnectionCount > 0) {
// All connections are in use. It'll be at least the keep alive duration 'til we run again.
// 当前无空闲连接
return keepAliveDurationNs;
} else {
// No connections, idle or in use.
cleanupRunning = false;
return -1;
}
}
closeQuietly(longestIdleConnection.socket());
// Cleanup again immediately.
return 0;
}
2.4 pruneAndGetAllocationCount:connection.transmitters维护了引用,这里回收基于引用计数。
/**
* Prunes any leaked transmitters and then returns the number of remaining live transmitters on
* {@code connection}. Transmitters are leaked if the connection is tracking them but the
* application code has abandoned them. Leak detection is imprecise and relies on garbage
* collection.
*/
private int pruneAndGetAllocationCount(RealConnection connection, long now) {
List<Reference<Transmitter>> references = connection.transmitters;
for (int i = 0; i < references.size(); ) {
Reference<Transmitter> reference = references.get(i);
if (reference.get() != null) {
i++;
continue;
}
// We've discovered a leaked transmitter. This is an application bug.
TransmitterReference transmitterRef = (TransmitterReference) reference;
String message = "A connection to " + connection.route().address().url()
+ " was leaked. Did you forget to close a response body?";
Platform.get().logCloseableLeak(message, transmitterRef.callStackTrace);
references.remove(i);
// 指定该连接不再受理请求
connection.noNewExchanges = true;
// If this was the last allocation, the connection is eligible for immediate eviction.
if (references.isEmpty()) {
connection.idleAtNanos = now - keepAliveDurationNs;
return 0;
}
}
return references.size();
}
2.5 TransmitterReference
static final class TransmitterReference extends WeakReference<Transmitter> {
/**
* Captures the stack trace at the time the Call is executed or enqueued. This is helpful for
* identifying the origin of connection leaks.
*/
final Object callStackTrace;
TransmitterReference(Transmitter referent, Object callStackTrace) {
super(referent);
this.callStackTrace = callStackTrace;
}
}