httpclient getPoolEntryBlocking连接池方法源码解读

 更新时间:2023年11月26日 09:14:58   作者:codecraft  
这篇文章主要为大家介绍了httpclient getPoolEntryBlocking连接池方法源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

本文主要研究一下httpclient的getPoolEntryBlocking

getPoolEntryBlocking

org/apache/http/pool/AbstractConnPool.java

private E getPoolEntryBlocking(
            final T route, final Object state,
            final long timeout, final TimeUnit timeUnit,
            final Future<E> future) throws IOException, InterruptedException, ExecutionException, TimeoutException {
        Date deadline = null;
        if (timeout > 0) {
            deadline = new Date (System.currentTimeMillis() + timeUnit.toMillis(timeout));
        }
        this.lock.lock();
        try {
            final RouteSpecificPool<T, C, E> pool = getPool(route);
            E entry;
            for (;;) {
                Asserts.check(!this.isShutDown, "Connection pool shut down");
                if (future.isCancelled()) {
                    throw new ExecutionException(operationAborted());
                }
                for (;;) {
                    entry = pool.getFree(state);
                    if (entry == null) {
                        break;
                    }
                    if (entry.isExpired(System.currentTimeMillis())) {
                        entry.close();
                    }
                    if (entry.isClosed()) {
                        this.available.remove(entry);
                        pool.free(entry, false);
                    } else {
                        break;
                    }
                }
                if (entry != null) {
                    this.available.remove(entry);
                    this.leased.add(entry);
                    onReuse(entry);
                    return entry;
                }
                // New connection is needed
                final int maxPerRoute = getMax(route);
                // Shrink the pool prior to allocating a new connection
                final int excess = Math.max(0, pool.getAllocatedCount() + 1 - maxPerRoute);
                if (excess > 0) {
                    for (int i = 0; i < excess; i++) {
                        final E lastUsed = pool.getLastUsed();
                        if (lastUsed == null) {
                            break;
                        }
                        lastUsed.close();
                        this.available.remove(lastUsed);
                        pool.remove(lastUsed);
                    }
                }
                if (pool.getAllocatedCount() < maxPerRoute) {
                    final int totalUsed = this.leased.size();
                    final int freeCapacity = Math.max(this.maxTotal - totalUsed, 0);
                    if (freeCapacity > 0) {
                        final int totalAvailable = this.available.size();
                        if (totalAvailable > freeCapacity - 1) {
                            if (!this.available.isEmpty()) {
                                final E lastUsed = this.available.removeLast();
                                lastUsed.close();
                                final RouteSpecificPool<T, C, E> otherpool = getPool(lastUsed.getRoute());
                                otherpool.remove(lastUsed);
                            }
                        }
                        final C conn = this.connFactory.create(route);
                        entry = pool.add(conn);
                        this.leased.add(entry);
                        return entry;
                    }
                }
                boolean success = false;
                try {
                    pool.queue(future);
                    this.pending.add(future);
                    if (deadline != null) {
                        success = this.condition.awaitUntil(deadline);
                    } else {
                        this.condition.await();
                        success = true;
                    }
                    if (future.isCancelled()) {
                        throw new ExecutionException(operationAborted());
                    }
                } finally {
                    // In case of 'success', we were woken up by the
                    // connection pool and should now have a connection
                    // waiting for us, or else we're shutting down.
                    // Just continue in the loop, both cases are checked.
                    pool.unqueue(future);
                    this.pending.remove(future);
                }
                // check for spurious wakeup vs. timeout
                if (!success && (deadline != null && deadline.getTime() <= System.currentTimeMillis())) {
                    break;
                }
            }
            throw new TimeoutException("Timeout waiting for connection");
        } finally {
            this.lock.unlock();
        }
    }
AbstractConnPool提供了getPoolEntryBlocking,lease内部就是通过这个方法来获取连接的。它主要是通过pool.getFree获取空闲连接,然后进行过期判断,再判断是否close,如果已经close则从available中移除,获取成功的话则从available移除,添加到leased然后返回。如果获取不到则先判断连接是否超出maxPerRoute,超出则先移除最近使用的,之后在没有超出maxPerRoute的条件下通过connFactory.create创建然后返回,超出则放入到pending中进行等待

InternalConnectionFactory

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

static class InternalConnectionFactory implements ConnFactory<HttpRoute, ManagedHttpClientConnection> {
        private final ConfigData configData;
        private final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory;
        InternalConnectionFactory(
                final ConfigData configData,
                final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory) {
            super();
            this.configData = configData != null ? configData : new ConfigData();
            this.connFactory = connFactory != null ? connFactory :
                ManagedHttpClientConnectionFactory.INSTANCE;
        }
        @Override
        public ManagedHttpClientConnection create(final HttpRoute route) throws IOException {
            ConnectionConfig config = null;
            if (route.getProxyHost() != null) {
                config = this.configData.getConnectionConfig(route.getProxyHost());
            }
            if (config == null) {
                config = this.configData.getConnectionConfig(route.getTargetHost());
            }
            if (config == null) {
                config = this.configData.getDefaultConnectionConfig();
            }
            if (config == null) {
                config = ConnectionConfig.DEFAULT;
            }
            return this.connFactory.create(route, config);
        }
    }
InternalConnectionFactory实现了ConnFactory接口,其create方法委托给ManagedHttpClientConnectionFactory.INSTANCE

ManagedHttpClientConnectionFactory

public class ManagedHttpClientConnectionFactory
        implements HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> {
    private static final AtomicLong COUNTER = new AtomicLong();
    public static final ManagedHttpClientConnectionFactory INSTANCE = new ManagedHttpClientConnectionFactory();
    private final Log log = LogFactory.getLog(DefaultManagedHttpClientConnection.class);
    private final Log headerLog = LogFactory.getLog("org.apache.http.headers");
    private final Log wireLog = LogFactory.getLog("org.apache.http.wire");
    private final HttpMessageWriterFactory<HttpRequest> requestWriterFactory;
    private final HttpMessageParserFactory<HttpResponse> responseParserFactory;
    private final ContentLengthStrategy incomingContentStrategy;
    private final ContentLengthStrategy outgoingContentStrategy;
    //......
    public ManagedHttpClientConnection create(final HttpRoute route, final ConnectionConfig config) {
        final ConnectionConfig cconfig = config != null ? config : ConnectionConfig.DEFAULT;
        CharsetDecoder charDecoder = null;
        CharsetEncoder charEncoder = null;
        final Charset charset = cconfig.getCharset();
        final CodingErrorAction malformedInputAction = cconfig.getMalformedInputAction() != null ?
                cconfig.getMalformedInputAction() : CodingErrorAction.REPORT;
        final CodingErrorAction unmappableInputAction = cconfig.getUnmappableInputAction() != null ?
                cconfig.getUnmappableInputAction() : CodingErrorAction.REPORT;
        if (charset != null) {
            charDecoder = charset.newDecoder();
            charDecoder.onMalformedInput(malformedInputAction);
            charDecoder.onUnmappableCharacter(unmappableInputAction);
            charEncoder = charset.newEncoder();
            charEncoder.onMalformedInput(malformedInputAction);
            charEncoder.onUnmappableCharacter(unmappableInputAction);
        }
        final String id = "http-outgoing-" + Long.toString(COUNTER.getAndIncrement());
        return new LoggingManagedHttpClientConnection(
                id,
                log,
                headerLog,
                wireLog,
                cconfig.getBufferSize(),
                cconfig.getFragmentSizeHint(),
                charDecoder,
                charEncoder,
                cconfig.getMessageConstraints(),
                incomingContentStrategy,
                outgoingContentStrategy,
                requestWriterFactory,
                responseParserFactory);
    }    
}
ManagedHttpClientConnectionFactory的create方法创建的是LoggingManagedHttpClientConnection,它继承了DefaultManagedHttpClientConnection增加了logging的特性,而DefaultManagedHttpClientConnection继承了DefaultBHttpClientConnection,声明实现了ManagedHttpClientConnection

小结

AbstractConnPool提供了getPoolEntryBlocking,lease内部就是通过这个方法来获取连接的。它主要是通过pool.getFree获取空闲连接,然后进行过期判断,再判断是否close,如果已经close则从available中移除,获取成功的话则从available移除,添加到leased然后返回。如果获取不到则先判断连接是否超出maxPerRoute,超出则先移除最近使用的,之后在没有超出maxPerRoute的条件下通过connFactory.create创建然后返回,超出则放入到pending中进行等待。

MainClientExec优先通过connManager.requestConnection是经过连接池管理的,如果连接不够用,通过connFactory.create创建新的ManagedHttpClientConnection,最后MainClientExec会再判断一下managedConn是否open,没有的话会通过establishRoute来建立连接(HttpClientConnectionManager.connect会创建socket然后进行connect然后bind到managedConn)

以上就是httpclient getPoolEntryBlocking连接池方法源码解读的详细内容,更多关于httpclient getPoolEntryBlocking的资料请关注脚本之家其它相关文章!

相关文章

  • 使用Feign传递请求头信息(Finchley版本)

    使用Feign传递请求头信息(Finchley版本)

    这篇文章主要介绍了使用Feign传递请求头信息(Finchley版本),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • java爬虫Jsoup主要类及功能使用详解

    java爬虫Jsoup主要类及功能使用详解

    这篇文章主要为大家介绍了java爬虫Jsoup主要类及功能使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • SpringBoot中MockMVC单元测试的实现

    SpringBoot中MockMVC单元测试的实现

    Mock是一种用于模拟和替换类的对象的方法,以便在单元测试中独立于外部资源进行测试,本文主要介绍了SpringBoot中MockMVC单元测试的实现,具有应该的参考价值,感兴趣的可以了解一下
    2024-02-02
  • Java中的拦截器、过滤器、监听器用法详解

    Java中的拦截器、过滤器、监听器用法详解

    这篇文章主要介绍了Java中的拦截器、过滤器、监听器用法,详细分析了Java拦截器、过滤器、监听器的功能、使用方法及相关注意事项,需要的朋友可以参考下
    2017-05-05
  • Spring Boot 中的 @ConditionalOnBean 注解作用及基本用法

    Spring Boot 中的 @ConditionalOnBean 注解作用及基

    在 Spring Boot 中,@ConditionalOnBean 可以帮助我们根据 是否存在特定 Bean 来 动态注册 Bean,广泛用于 按需加载、自动配置 等场景,本文给大家介绍Spring Boot 中的 @ConditionalOnBean 注解,感兴趣的朋友一起看看吧
    2025-04-04
  • SpringBoot接口返回结果封装方法实例详解

    SpringBoot接口返回结果封装方法实例详解

    在实际项目中,一般会把结果放在一个封装类中,封装类中包含http状态值,状态消息,以及实际的数据。这里主要记录两种方式,通过实例代码给大家介绍的非常详细,需要的朋友参考下吧
    2021-09-09
  • java中Servlet Cookie取不到值原因解决办法

    java中Servlet Cookie取不到值原因解决办法

    这篇文章主要介绍了java中Servlet Cookie取不到值原因解决办法的相关资料,需要的朋友可以参考下
    2017-06-06
  • Java equals()方法使用详解及总结

    Java equals()方法使用详解及总结

    这篇文章主要介绍了Java equals()方法使用详解及总结的相关资料,需要的朋友可以参考下
    2017-03-03
  • Spring 多线程事务控制的实践

    Spring 多线程事务控制的实践

    本文主要介绍了Spring 多线程事务控制的实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-09-09
  • Spring Boot 2.x中Actuator的一些知识点

    Spring Boot 2.x中Actuator的一些知识点

    这篇文章主要给大家介绍了关于Spring Boot 2.x中Actuator的一些知识点,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot 2.x具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-09-09

最新评论