首页
学习
活动
专区
圈层
工具
发布

HttpComponents HttpClient连接池(5)-可用性检查

上一篇文章里我们介绍了 httpclient 连接池中连接的重用,以及连接的 keep alive ,在这里我们主要介绍连接的可用性检查。

连接的可用性检查

对于 httpclient 连接池中的连接是可复用的,但是会存在这种情况,就是当我们从连接池中申请到连接的时候,很有可能连接不可用。比方说远端 server 关闭了连接,这样的话连接就不可用了。httpclient 提供了连接可用性检查机制,主要涉及了以下几个关键点:

  1. 何时进行可用性检查
  2. 如何进行可用性检查
  3. 可用性检查之后的处理

何时进行可用性检查

  • httpclient 在得到连接之后,使用连接之前提供可用性检查,核心代码在 MainClientExec 对象实例的 execute() 方法中:
代码语言:javascript
复制
if (config.isStaleConnectionCheckEnabled()) {
    // validate connection
    if (managedConn.isOpen()) {
        this.log.debug("Stale connection check");
        if (managedConn.isStale()) {
            this.log.debug("Stale connection detected");
            managedConn.close();
         }
    }
}
  • 由上述代码分析,可用性检查由RequestConfig 对象实例的 isStaleConnectionCheckEnabled() 方法来决定的。
  • 该值可以通过 RequestConfig.Builder 对象实例的 setStaleConnectionCheckEnabled() 方法完成设置。

如何进行可用性检查

  • ManagedHttpClientConnection 实例对象的 isStale() 方法来实现可用性检查,核心代码如下:
代码语言:javascript
复制
public boolean isStale() {
        if (!isOpen()) {
            return true;
        }
        try {
            final int bytesRead = fillInputBuffer(1);
            return bytesRead < 0;
        } catch (final SocketTimeoutException ex) {
            return false;
        } catch (final IOException ex) {
            return true;
        }
}

private int fillInputBuffer(final int timeout) throws IOException {
        final Socket socket = this.socketHolder.get();
        final int oldtimeout = socket.getSoTimeout();
        try {
            socket.setSoTimeout(timeout);
            return this.inBuffer.fillBuffer();
        } finally {
            socket.setSoTimeout(oldtimeout);
        }
}
  • 由上可知,设置原始 socket 的超时时间为1秒钟,然后进行读操作。如果可以读取数据或者读超时则代表连接可用,如果读不到数据或者有 IOException ,则代表连接不可用。

可用性检查之后的处理

  • 根据上面,如果检查发现连接不可用,那么就会调用 close() 方法。根据以前文章, close() 方法本质上是关闭原始 socket ,并且会设置ManagedHttpClientConnection 对象内部 bind 的原始 socket 为空。
  • 在MainClientExec 的 execute() 方法使用连接之前,会检查连接是否 open ,如果没有打开则调用 establishRoute() 方法重新建立连接。根据以前文章managedConn.isOpen() 本质就是判断 managedConn 对象内部 bind 的原始 socket 是否为空。在上一步中,连接不可用的时候,已经调用 close() 方法把内部 bind 的原始 socket 置为空,所以这里一定会重新建立连接。核心代码如下:
代码语言:javascript
复制
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;
     }
}
下一篇
举报
领券