Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >聊聊httpclient的validateAfterInactivity

聊聊httpclient的validateAfterInactivity

原创
作者头像
code4it
发布于 2023-11-18 13:01:41
发布于 2023-11-18 13:01:41
95600
代码可运行
举报
文章被收录于专栏:码匠的流水账码匠的流水账
运行总次数:0
代码可运行

本文主要研究一下httpclient的validateAfterInactivity

validateAfterInactivity

org/apache/http/pool/AbstractConnPool.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
public abstract class AbstractConnPool<T, C, E extends PoolEntry<T, C>>
                                               implements ConnPool<T, E>, ConnPoolControl<T> {

    private final Lock lock;
    private final Condition condition;
    private final ConnFactory<T, C> connFactory;
    private final Map<T, RouteSpecificPool<T, C, E>> routeToPool;
    private final Set<E> leased;
    private final LinkedList<E> available;
    private final LinkedList<Future<E>> pending;
    private final Map<T, Integer> maxPerRoute;

    private volatile boolean isShutDown;
    private volatile int defaultMaxPerRoute;
    private volatile int maxTotal;
    private volatile int validateAfterInactivity;

    public AbstractConnPool(
            final ConnFactory<T, C> connFactory,
            final int defaultMaxPerRoute,
            final int maxTotal) {
        super();
        this.connFactory = Args.notNull(connFactory, "Connection factory");
        this.defaultMaxPerRoute = Args.positive(defaultMaxPerRoute, "Max per route value");
        this.maxTotal = Args.positive(maxTotal, "Max total value");
        this.lock = new ReentrantLock();
        this.condition = this.lock.newCondition();
        this.routeToPool = new HashMap<T, RouteSpecificPool<T, C, E>>();
        this.leased = new HashSet<E>();
        this.available = new LinkedList<E>();
        this.pending = new LinkedList<Future<E>>();
        this.maxPerRoute = new HashMap<T, Integer>();
    }

    //......

    /**
     * @return the number of milliseconds
     * @since 4.4
     */
    public int getValidateAfterInactivity() {
        return this.validateAfterInactivity;
    }

    /**
     * @param ms the number of milliseconds
     * @since 4.4
     */
    public void setValidateAfterInactivity(final int ms) {
        this.validateAfterInactivity = ms;
    }    
}   

AbstractConnPool定义了validateAfterInactivity属性,与defaultMaxPerRoute、maxTotal不同,该属性没有在构造器参数中,而是提供了setter来设置

PoolingHttpClientConnectionManager

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
public class PoolingHttpClientConnectionManager
    implements HttpClientConnectionManager, ConnPoolControl<HttpRoute>, Closeable {

    public PoolingHttpClientConnectionManager(
        final HttpClientConnectionOperator httpClientConnectionOperator,
        final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
        final long timeToLive, final TimeUnit timeUnit) {
        super();
        this.configData = new ConfigData();
        this.pool = new CPool(new InternalConnectionFactory(
                this.configData, connFactory), 2, 20, timeToLive, timeUnit);
        this.pool.setValidateAfterInactivity(2000);
        this.connectionOperator = Args.notNull(httpClientConnectionOperator, "HttpClientConnectionOperator");
        this.isShutDown = new AtomicBoolean(false);
    }

    /**
     * Defines period of inactivity in milliseconds after which persistent connections must
     * be re-validated prior to being {@link #leaseConnection(java.util.concurrent.Future,
     *   long, java.util.concurrent.TimeUnit) leased} to the consumer. Non-positive value passed
     * to this method disables connection validation. This check helps detect connections
     * that have become stale (half-closed) while kept inactive in the pool.
     *
     * @see #leaseConnection(java.util.concurrent.Future, long, java.util.concurrent.TimeUnit)
     *
     * @since 4.4
     */
    public void setValidateAfterInactivity(final int ms) {
        pool.setValidateAfterInactivity(ms);
    }

    //......

}    

PoolingHttpClientConnectionManager默认设置pool的validateAfterInactivity为2000ms,另外也提供了setValidateAfterInactivity方法

lease

org/apache/http/pool/AbstractConnPool.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * {@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.
     */
    @Override
    public 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);

            @Override
            public 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;
            }

            @Override
            public boolean isCancelled() {
                return cancelled.get();
            }

            @Override
            public boolean isDone() {
                return done.get();
            }

            @Override
            public E get() throws InterruptedException, ExecutionException {
                try {
                    return get(0L, TimeUnit.MILLISECONDS);
                } catch (final TimeoutException ex) {
                    throw new ExecutionException(ex);
                }
            }

            @Override
            public 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);
                        }
                    }
                }
            }

        };
    }

AbstractConnPool的lease方法返回一个future,其get方法通过getPoolEntryBlocking(route, state, timeout, timeUnit, this)获取leasedEntry,之后判断validateAfterInactivity是否大于0,大于0则判断leasedEntry.getUpdated()+validateAfterInactivity是否小于等于当前时间,是则执行validate方法,validate不通过则close该entry然后release,然后继续循环执行getPoolEntryBlocking

validate

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    protected boolean validate(final CPoolEntry entry) {
        return !entry.getConnection().isStale();
    }

CPool的validate则是通过entry.getConnection().isStale()来判断

isStale

org/apache/http/impl/AbstractHttpClientConnection.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public boolean isStale() {
        if (!isOpen()) {
            return true;
        }
        if (isEof()) {
            return true;
        }
        try {
            this.inBuffer.isDataAvailable(1);
            return isEof();
        } catch (final SocketTimeoutException ex) {
            return false;
        } catch (final IOException ex) {
            return true;
        }
    }

AbstractHttpClientConnection的isStale先判断是否open,再判断是否eof,最后执行inBuffer.isDataAvailable(1),出现SocketTimeoutException返回false,出现IOException返回true,若没有异常返回isEof

小结

apache的httpclient的AbstractConnPool提供了validateAfterInactivity属性,默认是2000ms,它的作用是在连接池获取连接的时候进行判断,如果该entry的最后更新时间+validateAfterInactivity小于等于当前时间,则执行validate方法,validate不通过则继续循环获取连接。而validate方法则是通过connection的isStale来判断的。该属性有助于检测连接池中空闲连接的stale(half-closed)状态,避免真正使用的时候报错。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
聊聊httpclient的CPool
org/apache/http/pool/AbstractConnPool.java
code4it
2023/10/06
3730
聊聊httpclient的CPool
聊聊httpclient的CPool
org/apache/http/pool/AbstractConnPool.java
code4it
2023/10/05
3140
聊聊httpclient的getPoolEntryBlocking
org/apache/http/pool/AbstractConnPool.java
code4it
2023/11/25
2350
Http 持久连接与 HttpClient 连接池
HTTP协议是无状态的协议,即每一次请求都是互相独立的。因此它的最初实现是,每一个http请求都会打开一个tcp socket连接,当交互完毕后会关闭这个连接。
用户1257393
2018/07/30
2.5K0
Http 持久连接与 HttpClient 连接池
HttpComponents HttpClient连接池(3)-连接的释放
在上一篇文章里我们介绍了 httpclient 连接池中连接的申请,在这里我们主要介绍连接的和释放。
TA码字
2020/04/01
1.7K1
HttpComponents HttpClient连接池(2)-连接的申请
在上一篇文章里我们主要介绍了 httpclient 连接池的关键类和数据结构,在这里我们主要介绍http连接的申请和释放。
TA码字
2020/04/01
1.4K0
聊聊httpclient的staleConnectionCheckEnabled
本文主要研究一下httpclient的staleConnectionCheckEnabled
code4it
2023/11/24
5100
聊聊HttpClientBuilder
httpclient-4.5.10-sources.jar!/org/apache/http/impl/client/HttpClientBuilder.java
code4it
2023/10/04
5200
聊聊AsyncHttpClient的ListenableFuture
org/asynchttpclient/ListenableFuture.java
code4it
2023/12/17
2100
聊聊HttpClient的KeepAlive
org/apache/http/conn/ConnectionKeepAliveStrategy.java
code4it
2023/10/10
1.1K0
ElasticSearch源码分析之RestClient连接池
从上面的代码示例可以看出RestClient的实例化是依赖于RestClientBuilder的build方法,也就是应用了builder模式。HttpHost实例的构造方法入参为ip和端口。
山行AI
2020/04/22
9.5K0
ElasticSearch源码分析之RestClient连接池
SocketException:Connection reset 异常排查
这里使用Spring RestTemplate调外部接口查询结果。Spring RestTemplate 配置如下:
猫头虎
2024/04/08
2.3K1
网关使用 Apache HttpClient 连接池出现异常
两个主机建立网络连接是一个比较复杂的过程,涉及到多个数据包的交换。建立网络连接本身就很耗时间,而 Http 连接需要三次握手,开销就更大。但是可以直接使用已经建立好的 Http 连接,那么花费就比较小。耗时更短,从而提高访问的吞吐量。
BUG弄潮儿
2022/06/30
1.2K0
由一次线上故障来理解下TCP三握、四挥 & Java堆栈分析到源码的探秘
该服务主要是提供对外的代理接口,大部分接口都会调用第三方接口,获取数据后做聚合处理后,提供给客户端使用。
云爬虫技术研究笔记
2019/11/05
7970
由一次线上故障来理解下TCP三握、四挥 & Java堆栈分析到源码的探秘
HttpComponents HttpClient连接池(6)-连接清理
在上一篇文章里我们介绍了 httpclient 连接池中连接的可用性检查,在这里我们主要介绍空闲 http 连接的清理。对于连接池中的连接基本都是复用的,其中避免不了 server 端主动关闭连接,这个时候取出的连接自然是不可用的,当然可以通过上一篇文章中的可用性检查避免。但同时 httpclient 连接池也提供了 http 连接的清理策略,用来对连接进行清除。
TA码字
2020/04/01
3.5K0
httpclient参数配置
默认的话,是从response里头读timeout参数的,没有读到则设置为-1,这个代表无穷,这样设置是有点问题了,如果是https链接的话,则可能会经常报
code4it
2018/09/17
7.3K0
HTTP调用:你考虑到超时、重试、并发了吗?
与执行本地方法不同,进行 HTTP 调用本质上是通过 HTTP 协议进行一次网络请求。网络请求必然有超时的可能性,因此我们必须考虑到这三点:
小熊学Java
2023/07/16
3K0
HTTP调用:你考虑到超时、重试、并发了吗?
聊聊httpclient的connect
org/apache/http/conn/HttpClientConnectionOperator.java
code4it
2023/11/27
1880
聊聊httpclient的connect
聊聊httpclient的evict操作
org/apache/http/impl/client/HttpClientBuilder.java
code4it
2023/10/06
3650
聊聊httpclient的evict操作
聊聊httpclient的监控
micrometer-core-1.3.0-sources.jar!/io/micrometer/core/instrument/binder/httpcomponents/MicrometerHttpRequestExecutor.java
code4it
2023/10/07
6300
相关推荐
聊聊httpclient的CPool
更多 >
领券
一站式MCP教程库,解锁AI应用新玩法
涵盖代码开发、场景应用、自动测试全流程,助你从零构建专属AI助手
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档