httpclient ConnectionHolder连接池连接保持源码解析
作者:codecraft
序
本文主要研究一下httpclient的ConnectionHolder
ConnectionReleaseTrigger
org/apache/http/conn/ConnectionReleaseTrigger.java
/** * Interface for releasing a connection. This can be implemented by various * "trigger" objects which are associated with a connection, for example * a {@link EofSensorInputStream} or the {@link ManagedHttpClientConnection} itself. * <p> * The methods in this interface can safely be called multiple times. * The first invocation releases the connection, subsequent calls * are ignored. * * @since 4.0 */ public interface ConnectionReleaseTrigger { /** * Releases the connection with the option of keep-alive. This is a * "graceful" release and may cause IO operations for consuming the * remainder of a response entity. Use * {@link #abortConnection abortConnection} for a hard release. The * connection may be reused as specified by the duration. * * @throws IOException * in case of an IO problem. The connection will be released * anyway. */ void releaseConnection() throws IOException; /** * Releases the connection without the option of keep-alive. * This is a "hard" release that implies a shutdown of the connection. * Use {@link #releaseConnection()} for a graceful release. * * @throws IOException in case of an IO problem. * The connection will be released anyway. */ void abortConnection() throws IOException; }
ConnectionReleaseTrigger定义了releaseConnection、abortConnection方法
ConnectionHolder
org/apache/http/impl/execchain/ConnectionHolder.java
@Contract(threading = ThreadingBehavior.SAFE) class ConnectionHolder implements ConnectionReleaseTrigger, Cancellable, Closeable { private final Log log; private final HttpClientConnectionManager manager; private final HttpClientConnection managedConn; private final AtomicBoolean released; private volatile boolean reusable; private volatile Object state; private volatile long validDuration; private volatile TimeUnit timeUnit; public ConnectionHolder( final Log log, final HttpClientConnectionManager manager, final HttpClientConnection managedConn) { super(); this.log = log; this.manager = manager; this.managedConn = managedConn; this.released = new AtomicBoolean(false); } public boolean isReusable() { return this.reusable; } public void markReusable() { this.reusable = true; } public void markNonReusable() { this.reusable = false; } public void setState(final Object state) { this.state = state; } public void setValidFor(final long duration, final TimeUnit timeUnit) { synchronized (this.managedConn) { this.validDuration = duration; this.timeUnit = timeUnit; } } private void releaseConnection(final boolean reusable) { if (this.released.compareAndSet(false, true)) { synchronized (this.managedConn) { if (reusable) { this.manager.releaseConnection(this.managedConn, this.state, this.validDuration, this.timeUnit); } else { try { this.managedConn.close(); log.debug("Connection discarded"); } catch (final IOException ex) { if (this.log.isDebugEnabled()) { this.log.debug(ex.getMessage(), ex); } } finally { this.manager.releaseConnection( this.managedConn, null, 0, TimeUnit.MILLISECONDS); } } } } } @Override public void releaseConnection() { releaseConnection(this.reusable); } @Override public void abortConnection() { if (this.released.compareAndSet(false, true)) { synchronized (this.managedConn) { try { this.managedConn.shutdown(); log.debug("Connection discarded"); } catch (final IOException ex) { if (this.log.isDebugEnabled()) { this.log.debug(ex.getMessage(), ex); } } finally { this.manager.releaseConnection( this.managedConn, null, 0, TimeUnit.MILLISECONDS); } } } } @Override public boolean cancel() { final boolean alreadyReleased = this.released.get(); log.debug("Cancelling request execution"); abortConnection(); return !alreadyReleased; } public boolean isReleased() { return this.released.get(); } @Override public void close() throws IOException { releaseConnection(false); } }
ConnectionHolder实现了ConnectionReleaseTrigger接口,它提供了isReusable、markReusable、markNonReusable、setValidFor、releaseConnection、abortConnection、cancel、close等方法,其中releaseConnection是依赖reusable属性来决定是关闭连接还是归还连接,而abortConnection方法直接managedConn.shutdown(),然后在执行manager.releaseConnection
releaseConnection在连接复用则执行manager.releaseConnection,连接不复用先执行managedConn.close()再执行manager.releaseConnection(validDuratioin为0);
abortConnection先执行this.managedConn.shutdown(),再执行manager.releaseConnection(validDuratioin为0);
close与shutdown的区别在于close是优雅关闭,会试图flush内部的output buffer,shutdown是强制关闭,不会试图去flush内部的buffer
MainClientExec
org/apache/http/impl/execchain/MainClientExec.java
public CloseableHttpResponse execute( final HttpRoute route, final HttpRequestWrapper request, final HttpClientContext context, final HttpExecutionAware execAware) throws IOException, HttpException { //...... // The connection is in or can be brought to a re-usable state. if (reuseStrategy.keepAlive(response, context)) { // Set the idle duration of this connection final long duration = keepAliveStrategy.getKeepAliveDuration(response, context); if (this.log.isDebugEnabled()) { final String s; if (duration > 0) { s = "for " + duration + " " + TimeUnit.MILLISECONDS; } else { s = "indefinitely"; } this.log.debug("Connection can be kept alive " + s); } connHolder.setValidFor(duration, TimeUnit.MILLISECONDS); connHolder.markReusable(); } else { connHolder.markNonReusable(); } //...... // check for entity, release connection if possible final HttpEntity entity = response.getEntity(); if (entity == null || !entity.isStreaming()) { // connection not needed and (assumed to be) in re-usable state connHolder.releaseConnection(); return new HttpResponseProxy(response, null); } return new HttpResponseProxy(response, connHolder); //...... }
MainClientExec的execute方法在通过requestExecutor.execute(request, managedConn, context)获取到response的时候,会根据reuseStrategy.keepAlive(response, context)来判断该conn是reusable还是nonReusable的,最后在成功场景,entity为null或者不是streaming的会执行connHolder.releaseConnection(),异常场景执行connHolder.abortConnection()
DefaultClientConnectionReuseStrategy
org/apache/http/impl/client/DefaultClientConnectionReuseStrategy.java
public class DefaultClientConnectionReuseStrategy extends DefaultConnectionReuseStrategy { public static final DefaultClientConnectionReuseStrategy INSTANCE = new DefaultClientConnectionReuseStrategy(); @Override public boolean keepAlive(final HttpResponse response, final HttpContext context) { final HttpRequest request = (HttpRequest) context.getAttribute(HttpCoreContext.HTTP_REQUEST); if (request != null) { final Header[] connHeaders = request.getHeaders(HttpHeaders.CONNECTION); if (connHeaders.length != 0) { final TokenIterator ti = new BasicTokenIterator(new BasicHeaderIterator(connHeaders, null)); while (ti.hasNext()) { final String token = ti.nextToken(); if (HTTP.CONN_CLOSE.equalsIgnoreCase(token)) { return false; } } } } return super.keepAlive(response, context); } }
DefaultClientConnectionReuseStrategy继承了DefaultConnectionReuseStrategy,其keepAlive先判断response的header有无Connection: close,没有则返回false,有则调用super.keepAlive进行进一步判断(`对于http1.0的返回false)
小结
httpclient的ConnectionHolder实现了ConnectionReleaseTrigger接口,它提供了isReusable、markReusable、markNonReusable、setValidFor、releaseConnection、abortConnection、cancel、close等方法;releaseConnection在连接复用则执行manager.releaseConnection(validDuration为response的Keep-Alive返回的timeout参数,若没有则为-1
),连接不复用先执行managedConn.close()再执行manager.releaseConnection(validDuration为0
);abortConnection先执行this.managedConn.shutdown(),再执行manager.releaseConnection(validDuration为0
);
MainClientExec的execute方法在通过requestExecutor.execute(request, managedConn, context)获取到response的时候,会根据reuseStrategy.keepAlive(response, context)来判断该conn是reusable还是nonReusable的,最后在成功场景,entity为null或者不是streaming的会执行connHolder.releaseConnection(),异常场景执行connHolder.abortConnection()
DefaultClientConnectionReuseStrategy继承了DefaultConnectionReuseStrategy,其keepAlive先判断response的header有无Connection: close,没有则返回false,有则调用super.keepAlive进行进一步判断(`对于http1.0的返回false)
close与shutdown的区别在于close是优雅关闭,会试图flush内部的output buffer,shutdown是强制关闭,不会试图去flush内部的buffer
以上就是httpclient ConnectionHolder连接池连接保持源码解析的详细内容,更多关于httpclient ConnectionHolder连接保持的资料请关注脚本之家其它相关文章!