HttpComponents HttpClient连接池(4)-连接的重用和KeepAlive

上一篇文章里我们介绍了 httpclient 连接池中对于连接的申请和释放,这里我们主要介绍连接的重用,以及 keep alive。

http连接的重用

上一篇文章 http 连接的释放中 ConnectionHolder的releaseConnection() 方法会根据是否重用有不同的处理,那么 ConnectionHolders 是如何决定是否重用呢。就在 MainClientExec类 的 execute() 方法里,核心代码如下:

 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();
}

分析以上代码的核心本质是调用 reuseStrategy的keepAlive() 方法来决定是否重用。reuseStrategy的值 在 HttpClientBuilder 进行构建 httpclient 连接池的默认值为 DefaultClientConnectionReuseStrategy ,核心代码如下:

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);
}
  • 分析如上代码,如果 http 请求的请求头中包含项 Connection:Close ,那么不重用。

  • 另外该方法还调用了父类的keepAlive() 方法,其父类是 DefaultConnectionReuseStrategy 类型,对父类 keep alive有下面分析。

  • 对于父类的逻辑中,如果 http 响应的响应头中包含项 Connection:Close ,那么不重用。

  • 对于父类的逻辑中,如果 http 响应的响应头中包含项 Transfer-Encoding ,但是如果它的值不为 chunked ,那么不重用。

  • 对于父类的逻辑中,如果响应状态码为204表示没有数据,但是响应头里Content-Length的值大于0或者不为数字,或者 http 响应头里有 Transfer-Encoding项 ,那么不重用。

http连接的Keep Alive

  • 在上面的 http 连接重用代码中我们不难发现,在确定重用的基础上, keep alive 的时间长短是由keepAliveStrategy的getKeepAliveDuration()方法所决定的。对于 keepAliveStrategy 实例, 在 HttpClientBuilder 进行构建 httpclient 时默认策略为 DefaultConnectionKeepAliveStrategy ,其核心代码如下:

public long getKeepAliveDuration(final HttpResponse response, final HttpContext context) {
    Args.notNull(response, "HTTP response");
    final HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
    while (it.hasNext()) {
        final HeaderElement he = it.nextElement();
        final String param = he.getName();
        final String value = he.getValue();
        if (value != null && param.equalsIgnoreCase("timeout")) {
            try {
                return Long.parseLong(value) * 1000;
            } catch(final NumberFormatException ignore) {
            }
        }
    }
    return -1;
}
  • 通过分析上述代码,核心本质上是取得响应头 response header 项的 Keep-Alive: timeout 的值,单位为秒,如果没有那么取值-1。然后利用该值更新 CpoolEntry 对象的过期时间,如果该值为-1,则过期时间更新为Long.MAX_VALUE。

目前先写到这里,在下一篇文章里我们介绍 http 连接的可用性检查。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中使用HttpClient时,可以使用连接池来提高性能和可靠性。连接池可以管理多个HTTP连接重用已经建立的连接,从而避免了每次请求都需要重新建立连接的开销。 以下是在Spring Boot中使用HttpClient连接池的步骤: 1. 首先,需要在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency> ``` 2. 接下来,在application.properties文件中配置HttpClient连接池的参数,如下所示: ``` # HttpClient连接池最大连接数 http.maxTotal=200 # HttpClient连接池每个路由的最大连接数 http.maxPerRoute=20 # HttpClient连接池连接超时时间 http.connectionTimeout=5000 # HttpClient连接池请求超时时间 http.requestTimeout=5000 # HttpClient连接池等待数据超时时间 http.socketTimeout=5000 ``` 3. 然后,在Spring Boot的配置类中创建HttpClient连接池对象,并将其注入到需要使用的类中,如下所示: ``` @Configuration public class HttpClientConfig { @Value("${http.maxTotal}") private int maxTotal; @Value("${http.maxPerRoute}") private int maxPerRoute; @Value("${http.connectionTimeout}") private int connectionTimeout; @Value("${http.requestTimeout}") private int requestTimeout; @Value("${http.socketTimeout}") private int socketTimeout; @Bean public CloseableHttpClient httpClient() { PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); connectionManager.setMaxTotal(maxTotal); connectionManager.setDefaultMaxPerRoute(maxPerRoute); RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(connectionTimeout) .setConnectionRequestTimeout(requestTimeout) .setSocketTimeout(socketTimeout) .build(); return HttpClients.custom() .setConnectionManager(connectionManager) .setDefaultRequestConfig(requestConfig) .build(); } } ``` 4. 最后,在需要使用HttpClient的类中注入HttpClient对象,如下所示: ``` @Service public class MyService { @Autowired private CloseableHttpClient httpClient; public void doRequest() throws Exception { HttpGet httpGet = new HttpGet("http://www.example.com"); CloseableHttpResponse response = httpClient.execute(httpGet); // 处理响应 response.close(); } } ``` 这样,就可以使用HttpClient连接池来管理HTTP连接,提高性能和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值