Apache PoolingHttpClientConnectionManager 抛出非法状态异常

问题描述 投票:0回答:3

这是我的使用方法 -

private static final PoolingHttpClientConnectionManager connPool;

static {

        connPool = new PoolingHttpClientConnectionManager();
        // Increase max total connection to 200
        connPool.setMaxTotal(200);//configurable through app.properties
        // Increase default max connection per route to 50
        connPool.setDefaultMaxPerRoute(20);//configurable through app.properties

}

CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connPool) .build();

另外,我在 http GET 周围放置了一个 finally 块 -

finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                LOGGER.error(e.getMessage());   
            }
        }

这是我的堆栈跟踪 -

java.lang.IllegalStateException: Connection pool shut down
    at org.apache.http.util.Asserts.check(Asserts.java:34)
    at org.apache.http.pool.AbstractConnPool.lease(AbstractConnPool.java:169)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.requestConnection(PoolingHttpClientConnectionManager.java:217)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:157)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:194)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:85)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
    at com.A.B.C.CustomHttpClient.doGETAndValidate(CustomHttpClient.java:44)
    at com.A.B.C.SiteMonitorTask.monitorAndUpdateEndPoints(SiteMonitorTask.java:48)
    at com.A.B.C.SiteMonitorTask.run(SiteMonitorTask.java:37)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)

我正在使用 Quartz 来安排监视 Http 端点的作业。这是我的连接池配置

totalMaxHttpConn=200
maxHttpConnPerRoute=20

Maven 依赖..神器版本

httpclient 4.3.1
httpcore 4.3.1

编辑 - 好吧,通过在finally块中不关闭CloseableHttpClient,问题就消失了。任何人都可以告诉它为什么会这样吗? 为什么关闭客户端后连接池也会关闭?

上面的closeablehttpclient是不是池的句柄而不是单个conn

java connection-pooling apache-httpclient-4.x
3个回答
58
投票

在 4.4 版本中,方法

setConnectionManagerShared(boolean)
被添加到
HttpClientBuilder

如果将其设置为 true,客户端将不会关闭连接管理器。

HttpClients.custom()
            .setConnectionManager(Util.getConnectionManager()) // shared connection manager
            .setConnectionManagerShared(true)

11
投票

此行为是由于 HC 4.3 中的错误造成的。它已在 HC 4.4a1 中修复。从 4.4 开始

CloseableHttpClient#close
仅当由客户端独占时才应自动关闭连接池


0
投票

我找到的唯一解决方案来自这篇文章:https://www.eclipse.org/lists/jersey-dev/msg00135.html

基本上,只需重写

close()
shutdown()
PoolingHttpClientConnectionManager
方法,这样
close()
就会调用真正的
shutdown()
,而
shutdown()
什么都不做。

实际上我认为这更符合逻辑:当池一旦创建时,它就不应该永远关闭,即使池中的最后一个连接关闭时。而且,没有公开 API 可供再次打开它。

@Lock(LockType.WRITE)
@Produces
public HttpClientConnectionManager poolingHttpClientConnectionManager() {
    if (this.poolingHttpClientConnectionManager == null) {
        LOGGER.debug("Creating new PoolingHttpClientConnectionManager");
        this.poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager() {
            @Override
            public void close() {
                super.shutdown();
            }

            @Override
            public void shutdown() {
                // Disable shutdown of the pool. This will be called while last connection is closed after 2s,
                // but I don't even want this happen; instead, pool should never be shut down
            }
        };
        poolingHttpClientConnectionManager.setMaxTotal(MAX_CONNECTIONS); // and I found in 4.5.x, this is not respected in HttpConnPool constructor; it's still 20
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(MAX_CONNECTIONS); // and this still 2
    } else {
        LOGGER.debug("Returning old PoolingHttpClientConnectionManager");
    }
    return poolingHttpClientConnectionManager;
}

DEBUG
开启
org.apache.http.impl.conn.PoolingHttpClientConnectionManager
级别日志记录也有助于观察连接释放/租用/等详细信息。

© www.soinside.com 2019 - 2024. All rights reserved.