httpclient ConnectionHolder連接池連接保持源碼解析
序
本文主要研究一下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實(shí)現(xiàn)了ConnectionReleaseTrigger接口,它提供了isReusable、markReusable、markNonReusable、setValidFor、releaseConnection、abortConnection、cancel、close等方法,其中releaseConnection是依賴reusable屬性來決定是關(guān)閉連接還是歸還連接,而abortConnection方法直接managedConn.shutdown(),然后在執(zhí)行manager.releaseConnection
releaseConnection在連接復(fù)用則執(zhí)行manager.releaseConnection,連接不復(fù)用先執(zhí)行managedConn.close()再執(zhí)行manager.releaseConnection(validDuratioin為0);
abortConnection先執(zhí)行this.managedConn.shutdown(),再執(zhí)行manager.releaseConnection(validDuratioin為0);
close與shutdown的區(qū)別在于close是優(yōu)雅關(guān)閉,會試圖flush內(nèi)部的output buffer,shutdown是強(qiáng)制關(guān)閉,不會試圖去flush內(nèi)部的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的時(shí)候,會根據(jù)reuseStrategy.keepAlive(response, context)來判斷該conn是reusable還是nonReusable的,最后在成功場景,entity為null或者不是streaming的會執(zhí)行connHolder.releaseConnection(),異常場景執(zhí)行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,有則調(diào)用super.keepAlive進(jìn)行進(jìn)一步判斷(`對于http1.0的返回false)
小結(jié)
httpclient的ConnectionHolder實(shí)現(xiàn)了ConnectionReleaseTrigger接口,它提供了isReusable、markReusable、markNonReusable、setValidFor、releaseConnection、abortConnection、cancel、close等方法;releaseConnection在連接復(fù)用則執(zhí)行manager.releaseConnection(validDuration為response的Keep-Alive返回的timeout參數(shù),若沒有則為-1),連接不復(fù)用先執(zhí)行managedConn.close()再執(zhí)行manager.releaseConnection(validDuration為0);abortConnection先執(zhí)行this.managedConn.shutdown(),再執(zhí)行manager.releaseConnection(validDuration為0);
MainClientExec的execute方法在通過requestExecutor.execute(request, managedConn, context)獲取到response的時(shí)候,會根據(jù)reuseStrategy.keepAlive(response, context)來判斷該conn是reusable還是nonReusable的,最后在成功場景,entity為null或者不是streaming的會執(zhí)行connHolder.releaseConnection(),異常場景執(zhí)行connHolder.abortConnection()
DefaultClientConnectionReuseStrategy繼承了DefaultConnectionReuseStrategy,其keepAlive先判斷response的header有無Connection: close,沒有則返回false,有則調(diào)用super.keepAlive進(jìn)行進(jìn)一步判斷(`對于http1.0的返回false)
close與shutdown的區(qū)別在于close是優(yōu)雅關(guān)閉,會試圖flush內(nèi)部的output buffer,shutdown是強(qiáng)制關(guān)閉,不會試圖去flush內(nèi)部的buffer
以上就是httpclient ConnectionHolder連接池連接保持源碼解析的詳細(xì)內(nèi)容,更多關(guān)于httpclient ConnectionHolder連接保持的資料請關(guān)注腳本之家其它相關(guān)文章!
- httpclient connect連接請求方法源碼解讀
- httpclient getPoolEntryBlocking連接池方法源碼解讀
- httpclient staleConnectionCheckEnabled獲取連接流程解析
- 解讀httpclient的validateAfterInactivity連接池狀態(tài)檢測
- httpclient的disableConnectionState方法工作流程
- 探索HttpClient中的close方法及其對連接的影響
- HttpClient的RedirectStrategy重定向處理核心機(jī)制
- HttpClient HttpRoutePlanner接口確定請求目標(biāo)路由
相關(guān)文章
dubbo集成zipkin獲取Traceid的實(shí)現(xiàn)
這篇文章主要介紹了dubbo集成zipkin獲取Traceid的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
springboot掃碼登錄的簡單實(shí)現(xiàn)
本文主要介紹基于SpringBoot + Vue + Android實(shí)現(xiàn)的掃碼登錄,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
如何基于spring security實(shí)現(xiàn)在線用戶統(tǒng)計(jì)
這篇文章主要介紹了如何基于spring security實(shí)現(xiàn)在線用戶統(tǒng)計(jì),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
Java消息隊(duì)列RabbitMQ之消息回調(diào)詳解
這篇文章主要介紹了Java消息隊(duì)列RabbitMQ之消息回調(diào)詳解,消息回調(diào),其實(shí)就是消息確認(rèn)(生產(chǎn)者推送消息成功,消費(fèi)者接收消息成功) , 對于程序來說,發(fā)送者沒法確認(rèn)是否發(fā)送成功,需要的朋友可以參考下2023-07-07
MyBatis-Plus使用sl4j日志打印SQL的代碼詳解
以下是關(guān)于使用 Spring Boot 起始器替換 slf4j-api 和 logback 依賴的詳細(xì)步驟和注意事項(xiàng),包括 MyBatis-Plus 的默認(rèn)日志級別信息,需要的朋友可以參考下2024-10-10

