聊聊httpclient的staleConnectionCheckEnabled

本文主要研究一下httpclient的staleConnectionCheckEnabled

staleConnectionCheckEnabled

org/apache/http/client/config/RequestConfig.java

public class RequestConfig implements Cloneable {public static final RequestConfig DEFAULT = new Builder().build();private final boolean expectContinueEnabled;private final HttpHost proxy;private final InetAddress localAddress;private final boolean staleConnectionCheckEnabled;//....../*** Determines whether stale connection check is to be used. The stale* connection check can cause up to 30 millisecond overhead per request and* should be used only when appropriate. For performance critical* operations this check should be disabled.* <p>* Default: {@code false} since 4.4* </p>** @deprecated (4.4) Use {@link*   org.apache.http.impl.conn.PoolingHttpClientConnectionManager#getValidateAfterInactivity()}*/@Deprecatedpublic boolean isStaleConnectionCheckEnabled() {return staleConnectionCheckEnabled;}   public static class Builder {private boolean expectContinueEnabled;private HttpHost proxy;private InetAddress localAddress;private boolean staleConnectionCheckEnabled;//......Builder() {super();this.staleConnectionCheckEnabled = false;this.redirectsEnabled = true;this.maxRedirects = 50;this.relativeRedirectsAllowed = true;this.authenticationEnabled = true;this.connectionRequestTimeout = -1;this.connectTimeout = -1;this.socketTimeout = -1;this.contentCompressionEnabled = true;this.normalizeUri = true;}        /*** @deprecated (4.4) Use {@link*   org.apache.http.impl.conn.PoolingHttpClientConnectionManager#setValidateAfterInactivity(int)}*/@Deprecatedpublic Builder setStaleConnectionCheckEnabled(final boolean staleConnectionCheckEnabled) {this.staleConnectionCheckEnabled = staleConnectionCheckEnabled;return this;}  //......}       
}    

RequestConfig定義了staleConnectionCheckEnabled屬性,在4.4版本廢棄了,默認為false,替換設置是org.apache.http.impl.conn.PoolingHttpClientConnectionManager.setValidateAfterInactivity(int);Builder方法也提供了setStaleConnectionCheckEnabled方法

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 {Args.notNull(route, "HTTP route");Args.notNull(request, "HTTP request");Args.notNull(context, "HTTP context");AuthState targetAuthState = context.getTargetAuthState();if (targetAuthState == null) {targetAuthState = new AuthState();context.setAttribute(HttpClientContext.TARGET_AUTH_STATE, targetAuthState);}AuthState proxyAuthState = context.getProxyAuthState();if (proxyAuthState == null) {proxyAuthState = new AuthState();context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, proxyAuthState);}if (request instanceof HttpEntityEnclosingRequest) {RequestEntityProxy.enhance((HttpEntityEnclosingRequest) request);}Object userToken = context.getUserToken();final ConnectionRequest connRequest = connManager.requestConnection(route, userToken);if (execAware != null) {if (execAware.isAborted()) {connRequest.cancel();throw new RequestAbortedException("Request aborted");}execAware.setCancellable(connRequest);}final RequestConfig config = context.getRequestConfig();final HttpClientConnection managedConn;try {final int timeout = config.getConnectionRequestTimeout();managedConn = connRequest.get(timeout > 0 ? timeout : 0, TimeUnit.MILLISECONDS);} catch(final InterruptedException interrupted) {Thread.currentThread().interrupt();throw new RequestAbortedException("Request aborted", interrupted);} catch(final ExecutionException ex) {Throwable cause = ex.getCause();if (cause == null) {cause = ex;}throw new RequestAbortedException("Request execution failed", cause);}context.setAttribute(HttpCoreContext.HTTP_CONNECTION, managedConn);if (config.isStaleConnectionCheckEnabled()) {// validate connectionif (managedConn.isOpen()) {this.log.debug("Stale connection check");if (managedConn.isStale()) {this.log.debug("Stale connection detected");managedConn.close();}}}final ConnectionHolder connHolder = new ConnectionHolder(this.log, this.connManager, managedConn);try {if (execAware != null) {execAware.setCancellable(connHolder);}HttpResponse response;for (int execCount = 1;; execCount++) {if (execCount > 1 && !RequestEntityProxy.isRepeatable(request)) {throw new NonRepeatableRequestException("Cannot retry request " +"with a non-repeatable request entity.");}if (execAware != null && execAware.isAborted()) {throw new RequestAbortedException("Request aborted");}if (!managedConn.isOpen()) {this.log.debug("Opening connection " + route);try {establishRoute(proxyAuthState, managedConn, route, request, context);} catch (final TunnelRefusedException ex) {if (this.log.isDebugEnabled()) {this.log.debug(ex.getMessage());}response = ex.getResponse();break;}}context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);response = requestExecutor.execute(request, managedConn, context);//......}}        //......//......}    

MainClientExec的execute先通過connManager.requestConnection獲取ConnectionRequest,然后通過connRequest.get(timeout > 0 ? timeout : 0, TimeUnit.MILLISECONDS)獲取managedConn,之后判斷requestConfig的isStaleConnectionCheckEnabled,為true的話,會執行連接的校驗,先判斷是否open,再判斷是否stale,為stale的話則執行close;在managedConn關閉的時候,會通過establishRoute再進行連接

establishRoute

org/apache/http/impl/execchain/MainClientExec.java

    /*** Establishes the target route.*/void establishRoute(final AuthState proxyAuthState,final HttpClientConnection managedConn,final HttpRoute route,final HttpRequest request,final HttpClientContext context) throws HttpException, IOException {final RequestConfig config = context.getRequestConfig();final int timeout = config.getConnectTimeout();final RouteTracker tracker = new RouteTracker(route);int step;do {final HttpRoute fact = tracker.toRoute();step = this.routeDirector.nextStep(route, fact);switch (step) {case HttpRouteDirector.CONNECT_TARGET:this.connManager.connect(managedConn,route,timeout > 0 ? timeout : 0,context);tracker.connectTarget(route.isSecure());break;case HttpRouteDirector.CONNECT_PROXY:this.connManager.connect(managedConn,route,timeout > 0 ? timeout : 0,context);final HttpHost proxy  = route.getProxyHost();tracker.connectProxy(proxy, route.isSecure() && !route.isTunnelled());break;case HttpRouteDirector.TUNNEL_TARGET: {final boolean secure = createTunnelToTarget(proxyAuthState, managedConn, route, request, context);this.log.debug("Tunnel to target created.");tracker.tunnelTarget(secure);}   break;case HttpRouteDirector.TUNNEL_PROXY: {// The most simple example for this case is a proxy chain// of two proxies, where P1 must be tunnelled to P2.// route: Source -> P1 -> P2 -> Target (3 hops)// fact:  Source -> P1 -> Target       (2 hops)final int hop = fact.getHopCount()-1; // the hop to establishfinal boolean secure = createTunnelToProxy(route, hop, context);this.log.debug("Tunnel to proxy created.");tracker.tunnelProxy(route.getHopTarget(hop), secure);}   break;case HttpRouteDirector.LAYER_PROTOCOL:this.connManager.upgrade(managedConn, route, context);tracker.layerProtocol(route.isSecure());break;case HttpRouteDirector.UNREACHABLE:throw new HttpException("Unable to establish route: " +"planned = " + route + "; current = " + fact);case HttpRouteDirector.COMPLETE:this.connManager.routeComplete(managedConn, route, context);break;default:throw new IllegalStateException("Unknown step indicator "+ step + " from RouteDirector.");}} while (step > HttpRouteDirector.COMPLETE);}

establishRoute方法在循環里頭通過connManager.connect建立連接

requestConnection

org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java

    public ConnectionRequest requestConnection(final HttpRoute route,final Object state) {Args.notNull(route, "HTTP route");if (this.log.isDebugEnabled()) {this.log.debug("Connection request: " + format(route, state) + formatStats(route));}final Future<CPoolEntry> future = this.pool.lease(route, state, null);return new ConnectionRequest() {@Overridepublic boolean cancel() {return future.cancel(true);}@Overridepublic HttpClientConnection get(final long timeout,final TimeUnit timeUnit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException {final HttpClientConnection conn = leaseConnection(future, timeout, timeUnit);if (conn.isOpen()) {final HttpHost host;if (route.getProxyHost() != null) {host = route.getProxyHost();} else {host = route.getTargetHost();}final SocketConfig socketConfig = resolveSocketConfig(host);conn.setSocketTimeout(socketConfig.getSoTimeout());}return conn;}};}

PoolingHttpClientConnectionManager的requestConnection返回的ConnectionRequest的get方法是通過leaseConnection(future, timeout, timeUnit)來獲取連接的,而leaseConnection依賴的是pool.lease(route, state, null)返回的future

lease

org/apache/http/pool/AbstractConnPool.java

    /*** {@inheritDoc}* <p>* Please note that this class does not maintain its own pool of execution* {@link Thread}s. Therefore, one <b>must</b> call {@link Future#get()}* or {@link Future#get(long, TimeUnit)} method on the {@link Future}* returned by this method in order for the lease operation to complete.*/@Overridepublic Future<E> lease(final T route, final Object state, final FutureCallback<E> callback) {Args.notNull(route, "Route");Asserts.check(!this.isShutDown, "Connection pool shut down");return new Future<E>() {private final AtomicBoolean cancelled = new AtomicBoolean(false);private final AtomicBoolean done = new AtomicBoolean(false);private final AtomicReference<E> entryRef = new AtomicReference<E>(null);@Overridepublic boolean cancel(final boolean mayInterruptIfRunning) {if (done.compareAndSet(false, true)) {cancelled.set(true);lock.lock();try {condition.signalAll();} finally {lock.unlock();}if (callback != null) {callback.cancelled();}return true;}return false;}@Overridepublic boolean isCancelled() {return cancelled.get();}@Overridepublic boolean isDone() {return done.get();}@Overridepublic E get() throws InterruptedException, ExecutionException {try {return get(0L, TimeUnit.MILLISECONDS);} catch (final TimeoutException ex) {throw new ExecutionException(ex);}}@Overridepublic E get(final long timeout, final TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {for (;;) {synchronized (this) {try {final E entry = entryRef.get();if (entry != null) {return entry;}if (done.get()) {throw new ExecutionException(operationAborted());}final E leasedEntry = getPoolEntryBlocking(route, state, timeout, timeUnit, this);if (validateAfterInactivity > 0)  {if (leasedEntry.getUpdated() + validateAfterInactivity <= System.currentTimeMillis()) {if (!validate(leasedEntry)) {leasedEntry.close();release(leasedEntry, false);continue;}}}if (done.compareAndSet(false, true)) {entryRef.set(leasedEntry);done.set(true);onLease(leasedEntry);if (callback != null) {callback.completed(leasedEntry);}return leasedEntry;} else {release(leasedEntry, true);throw new ExecutionException(operationAborted());}} catch (final IOException ex) {if (done.compareAndSet(false, true)) {if (callback != null) {callback.failed(ex);}}throw new ExecutionException(ex);}}}}};}

lease返回的future的get(final long timeout, final TimeUnit timeUnit)方法在一個循環里頭去獲取連接,內部是通過getPoolEntryBlocking獲取到leasedEntry,然后在validateAfterInactivity大于0的時候進行連接校驗,在leasedEntry.getUpdated() + validateAfterInactivity <= System.currentTimeMillis()的時候進行validate,校驗不成功的話進行關閉掉leasedEntry,然后release掉leasedEntry,然后繼續循環獲取下一個連接

小結

httpclient的RequestConfig提供了staleConnectionCheckEnabled屬性用于在請求獲取到連接的時候進行連接檢測,不過這個屬性在4.4版本被廢棄了,并默認設置為false,替換設置是org.apache.http.impl.conn.PoolingHttpClientConnectionManager.setValidateAfterInactivity(int),它是在ConnectionRequest的lease方法里頭根據leasedEntry.getUpdated() + validateAfterInactivity判斷是否需要校驗連接,若需要且校驗不通過則循環繼續獲取;而staleConnectionCheckEnabled則是在requestConnection之后根據RequestConfig的isStaleConnectionCheckEnabled來判斷,然后進行連接校驗,校驗不通過則關閉managedConn,最后會在判斷如果managedConn.isOpen()為false,則執行establishRoute,在循環里頭通過connManager.connect來建立新連接。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/165847.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/165847.shtml
英文地址,請注明出處:http://en.pswp.cn/news/165847.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【ARM 嵌入式 編譯 Makefile 系列 18 -- Makefile 中的 export 命令詳細介紹】

文章目錄 Makefile 中的 export 命令詳細介紹Makefile 使用 export導出與未導出變量的區別示例&#xff1a;導出變量以供子 Makefile 使用 Makefile 中的 export 命令詳細介紹 在 Makefile 中&#xff0c;export 命令用于將變量從 Makefile 導出到由 Makefile 啟動的子進程的環…

qgis添加wms服務

例如添加geoserver的wms服務 左右瀏覽器-WMS/WMTS-右鍵-新建連接 URL添加geoserver的wms地址 http://{ip}:{port}/geoserver/{workspace}/wms 展開wms目錄&#xff0c;雙擊相應圖層即可打開

Spark---基于Yarn模式提交任務

Yarn模式兩種提交任務方式 一、yarn-client提交任務方式 1、提交命令 ./spark-submit --master yarn --class org.apache.spark.examples.SparkPi ../examples/jars/spark-examples_2.11-2.3.1.jar 100 或者 ./spark-submit --master yarn–client --class org.apache.s…

三菱PLC應用[集錦]

三菱PLC應用[集錦] 如何判斷用PNP還是NPN的個人工作心得 10&#xff5e;30VDC接近開關與PLC連接時&#xff0c;如何判斷用PNP還是NPN的個人工作心得: 對于PLC的開關量輸入回路。我個人感覺日本三菱的要好得多&#xff0c;甚至比西門子等赫赫大名的PLC都要實用和可靠&#xff01…

vulnhub4

靶機地址: https://download.vulnhub.com/admx/AdmX_new.7z 信息收集 fscan 掃一下 ┌──(kali?kali)-[~/Desktop/Tools/fscan] └─$ ./fscan_amd64 -h 192.168.120.138 ___ _ / _ \ ___ ___ _ __ __ _ ___| | __ / /_\/____/ __|/ …

LeetCode | 622. 設計循環隊列

LeetCode | 622. 設計循環隊列 OJ鏈接 思路&#xff1a; 我們這里有一個思路&#xff1a; 插入數據&#xff0c;bank往后走 刪除數據&#xff0c;front往前走 再插入數據&#xff0c;就循環了 那上面這個方法可行嗎&#xff1f; 怎么判斷滿&#xff0c;怎么判斷空&#xff1…

模電知識點總結(二)二極管

系列文章目錄 文章目錄 系列文章目錄二極管二極管電路分析方法理想模型恒壓降模型折線模型小信號模型高頻/開關 二極管應用整流限幅/鉗位開關齊納二極管變容二極管肖特基二極管光電器件光電二極管發光二極管激光二極管太陽能電池 二極管 硅二極管&#xff1a;死區電壓&#xf…

今年注冊電氣工程師考試亂象及就業前景分析

1、注冊電氣工程師掛靠價格 # 2011年以前約為5萬一年&#xff0c;2011年開始強制實施注冊電氣執業制度&#xff0c;證書掛靠價格開始了飛漲&#xff0c;2013年達到巔峰&#xff0c;供配電15萬一年&#xff0c;發輸變電20-25萬一年&#xff0c;這哪里是證書&#xff0c;簡直就是…

Docker kill 命令

docker kill&#xff1a;殺死一個或多個正在運行的容器。 語法&#xff1a; docker kill [OPTIONS] CONTAINER [CONTAINER...]OPTIONS說明&#xff1a; -s&#xff1a;向容器發送一個信號 描述&#xff1a; docker kill子命令會殺死一個或多個容器。容器內的主進程被發送S…

C語言數組的距離(ZZULIOJ1200:數組的距離)

題目描述 已知元素從小到大排列的兩個數組x[]和y[]&#xff0c; 請寫出一個程序算出兩個數組彼此之間差的絕對值中最小的一個&#xff0c;這叫做數組的距離 。 輸入&#xff1a;第一行為兩個整數m, n(1≤m, n≤1000)&#xff0c;分別代表數組f[], g[]的長度。第二行有m個元素&a…

如何在Simulink中使用syms?換個思路解決報錯:Function ‘syms‘ not supported for code generation.

問題描述 在Simulink中的User defined function使用syms函數&#xff0c;報錯simulink無法使用外部函數。 具體來說&#xff1a; 我想在Predefined function定義如下符號函數作為輸入信號&#xff0c;在后續模塊傳入函數參數賦值&#xff0c;以實現一次定義多次使用&#xf…

014:MyString

題目 描述 補足MyString類&#xff0c;使程序輸出指定結果 #include <iostream> #include <string> #include <cstring> using namespace std; class MyString {char * p; public:MyString(const char * s) {if( s) {p new char[strlen(s) 1];strcpy(p,…

最小二乘線性回歸

? 線性回歸&#xff08;linear regression&#xff09;&#xff1a;試圖學得一個線性模型以盡可能準確地預測實際值的輸出。 以一個例子來說明線性回歸&#xff0c;假設銀行貸款會根據 年齡 和 工資 來評估可放款的額度。即&#xff1a; ? 數據&#xff1a;工資和年齡&…

python將模塊進行打包

模塊名稱為&#xff1a;my_module 目錄結構&#xff1a; my_modulemy_module__init__.pymy_module_main.pysetup.pypython setup.pu sdist bdist_wheel生成tar.gz包和whl文件用于安裝 """ python setup.py sdist bdist_wheel """from setuptoo…

LeeCode前端算法基礎100題(2)- 最多水的容器

一、問題詳情&#xff1a; 給定一個長度為 n 的整數數組 height 。有 n 條垂線&#xff0c;第 i 條線的兩個端點是 (i, 0) 和 (i, height[i]) 。 找出其中的兩條線&#xff0c;使得它們與 x 軸共同構成的容器可以容納最多的水。 返回容器可以儲存的最大水量。 說明&#xff1a;…

案例025:基于微信小程序的移動學習平臺的設計與實現

文末獲取源碼 開發語言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 數據庫&#xff1a;mysql 5.7 開發軟件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序開發軟件&#xff1a;HBuilder X 小程序…

[C++歷練之路]優先級隊列||反向迭代器的模擬實現

W...Y的主頁 &#x1f60a; 代碼倉庫分享&#x1f495; &#x1f354;前言&#xff1a; 在C的宇宙中&#xff0c;優先隊列似乎是一座巨大的寶庫&#xff0c;藏匿著算法的珍寶。而就在這片代碼的天空下&#xff0c;我們不僅可以探索優先隊列的神奇&#xff0c;還能夠揭開反向迭…

shutil和fileinput模塊:文件操作的最佳實踐

在Python中&#xff0c;shutil和fileinput模塊是處理文件和輸入/輸出(I/O)操作的有力工具。shutil模塊提供了一種在Python中操作文件的高級接口&#xff0c;而fileinput模塊則允許我們輕松地讀取多個輸入流。 shutil模塊 shutil模塊是Python的標準庫之一&#xff0c;提供了很…

【【Linux系統下常用指令學習 之 二 】】

Linux系統下常用指令學習 之 二 文件查詢和搜索 文件的查詢和搜索也是最常用的操作&#xff0c;在嵌入式 Linux 開發中常常需要在 Linux 源碼文件中查詢某個文件是否存在&#xff0c;或者搜索哪些文件都調用了某個函數等等。 1、命令 find find 命令用于在目錄結構中查找文件…

BUUCTF [ACTF新生賽2020]outguess 1

BUUCTF:https://buuoj.cn/challenges 題目描述&#xff1a; 得到的 flag 請包上 flag{} 提交。 密文&#xff1a; 下載附件&#xff0c;得到一堆文件。 解題思路&#xff1a; 1、根據題目和flag.txt文件提示&#xff0c;猜測為outguess隱寫。 outguess下載安裝 kail 終端命…