1 public abstract class PoolEntry<T, C> { 2 3 private final String id; 4 private final T route; //路由 5 private final C conn; //http连接 6 private final long created; //创建时间 7 private final long validityDeadline; 8 9 private long updated; 10 11 private long expiry; 12 13 private volatile Object state; 14 15 }
构造方法:
1 public PoolEntry(final String id, final T route, final C conn, 2 final long timeToLive, final TimeUnit tunit) { 3 super(); 4 Args.notNull(route, "Route"); 5 Args.notNull(conn, "Connection"); 6 Args.notNull(tunit, "Time unit"); 7 this.id = id; 8 this.route = route; 9 this.conn = conn; 10 this.created = System.currentTimeMillis(); 11 this.updated = this.created; 12 if (timeToLive > 0) { 13 final long deadline = this.created + tunit.toMillis(timeToLive); 14 // If the above overflows then default to Long.MAX_VALUE 15 this.validityDeadline = deadline > 0 ? deadline : Long.MAX_VALUE; 16 } else { 17 this.validityDeadline = Long.MAX_VALUE; 18 } 19 this.expiry = this.validityDeadline; 20 }
更新过期时间:
1 public synchronized void updateExpiry(final long time, final TimeUnit tunit) { 2 Args.notNull(tunit, "Time unit"); 3 this.updated = System.currentTimeMillis(); 4 final long newExpiry; 5 if (time > 0) { 6 newExpiry = this.updated + tunit.toMillis(time); 7 } else { 8 newExpiry = Long.MAX_VALUE; 9 } 10 this.expiry = Math.min(newExpiry, this.validityDeadline); 11 }
1、http连接池管理一个连接对象,其实管理的是一个PoolEntry实例;
2、什么时候更新PoolEntry实例信息,比如过期时间,状态等?
在释放连接的时候会更新实例信息;
具体在:PoolingHttpClientConnectionManager.releaseConnection(final HttpClientConnection managedConn, final Object state, final long keepalive, final TimeUnit tunit) 方法中调用;但是这个方法是我们在释放response是调用的。
1 public void releaseConnection( 2 final HttpClientConnection managedConn, 3 final Object state, 4 final long keepalive, final TimeUnit tunit) { 5 Args.notNull(managedConn, "Managed connection"); 6 synchronized (managedConn) { 7 final CPoolEntry entry = CPoolProxy.detach(managedConn); 8 if (entry == null) { 9 return; 10 } 11 final ManagedHttpClientConnection conn = entry.getConnection(); 12 try { 13 if (conn.isOpen()) { 14 final TimeUnit effectiveUnit = tunit != null ? tunit : TimeUnit.MILLISECONDS; 15 entry.setState(state); 16 entry.updateExpiry(keepalive, effectiveUnit); //keepalive 参数表示长连接的过期时间,在客户端通过keepAliveStrategy参数设置 17 if (this.log.isDebugEnabled()) { 18 final String s; 19 if (keepalive > 0) { 20 s = "for " + (double) effectiveUnit.toMillis(keepalive) / 1000 + " seconds"; 21 } else { 22 s = "indefinitely"; 23 } 24 this.log.debug("Connection " + format(entry) + " can be kept alive " + s); 25 } 26 conn.setSocketTimeout(0); 27 } 28 } finally { 29 this.pool.release(entry, conn.isOpen() && entry.isRouteComplete()); 30 if (this.log.isDebugEnabled()) { 31 this.log.debug("Connection released: " + format(entry) + formatStats(entry.getRoute())); 32 } 33 } 34 } 35 }
3、PoolingHttpClientConnectionManager 连接池参数 validateAfterInactivity说明:
当从连接池中拿到一个poolEntry时,如果validateAfterInactivity参数大于0 且 这个PoolEntry实例的updated加validateAfterInactivity小于等于当前时间,会检查这个连接(httpEntry实例中的con)的连接状态 state 值;
1 org.apache.http.impl.BHttpConnectionBase 2 public boolean isStale() { 3 if (!isOpen()) { 4 return true; 5 } 6 try { 7 final int bytesRead = fillInputBuffer(1); 8 return bytesRead < 0; 9 } catch (final SocketTimeoutException ex) { 10 return false; 11 } catch (final IOException ex) { 12 return true; 13 } 14 }
4、PoolingHttpClientConnectionManager 的关闭空闲超时连接方法:
指PoolEntry实例的更新时间加 空闲时间(设置)大于等于 当前时间,表示这个连接超过空闲时间
1 public void closeIdleConnections(final long idleTimeout, final TimeUnit tunit) { 2 if (this.log.isDebugEnabled()) { 3 this.log.debug("Closing connections idle longer than " + idleTimeout + " " + tunit); 4 } 5 this.pool.closeIdle(idleTimeout, tunit); 6 }
5、PoolingHttpClientConnectionManager 的关闭过期连接方法:
指当前时间大于PoolEntry实例的expiry值
1 public void closeExpiredConnections() { 2 this.log.debug("Closing expired connections"); 3 this.pool.closeExpired(); 4 }
6、closeIdleConnections() 和 closeExpiredConnections() 对外提供,需要用户自己去调用,我们一般维护一个独立的线程去调用,清除空闲的连接和过期连接。