美文网首页
聊聊HttpClient的close

聊聊HttpClient的close

作者: go4it | 来源:发表于2023-10-25 21:26 被阅读0次

    本文主要研究一下HttpClient的close

    CloseableHttpClient

    org/apache/http/impl/client/CloseableHttpClient.java

    @Contract(threading = ThreadingBehavior.SAFE)
    public abstract class CloseableHttpClient implements HttpClient, Closeable {
    
        @Override
        public <T> T execute(final HttpHost target, final HttpRequest request,
                final ResponseHandler<? extends T> responseHandler, final HttpContext context)
                throws IOException, ClientProtocolException {
            Args.notNull(responseHandler, "Response handler");
    
            final CloseableHttpResponse response = execute(target, request, context);
            try {
                final T result = responseHandler.handleResponse(response);
                final HttpEntity entity = response.getEntity();
                EntityUtils.consume(entity);
                return result;
            } catch (final ClientProtocolException t) {
                // Try to salvage the underlying connection in case of a protocol exception
                final HttpEntity entity = response.getEntity();
                try {
                    EntityUtils.consume(entity);
                } catch (final Exception t2) {
                    // Log this exception. The original exception is more
                    // important and will be thrown to the caller.
                    this.log.warn("Error consuming content after an exception.", t2);
                }
                throw t;
            } finally {
                response.close();
            }
        }
    
        //......
    }
    

    CloseableHttpClient声明实现HttpClient, Closeable接口

    InternalHttpClient

    org/apache/http/impl/client/InternalHttpClient.java

    @Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
    @SuppressWarnings("deprecation")
    class InternalHttpClient extends CloseableHttpClient implements Configurable {
    
        private final Log log = LogFactory.getLog(getClass());
    
        private final ClientExecChain execChain;
        private final HttpClientConnectionManager connManager;
        private final HttpRoutePlanner routePlanner;
        private final Lookup<CookieSpecProvider> cookieSpecRegistry;
        private final Lookup<AuthSchemeProvider> authSchemeRegistry;
        private final CookieStore cookieStore;
        private final CredentialsProvider credentialsProvider;
        private final RequestConfig defaultConfig;
        private final List<Closeable> closeables;
    
        public InternalHttpClient(
                final ClientExecChain execChain,
                final HttpClientConnectionManager connManager,
                final HttpRoutePlanner routePlanner,
                final Lookup<CookieSpecProvider> cookieSpecRegistry,
                final Lookup<AuthSchemeProvider> authSchemeRegistry,
                final CookieStore cookieStore,
                final CredentialsProvider credentialsProvider,
                final RequestConfig defaultConfig,
                final List<Closeable> closeables) {
            super();
            Args.notNull(execChain, "HTTP client exec chain");
            Args.notNull(connManager, "HTTP connection manager");
            Args.notNull(routePlanner, "HTTP route planner");
            this.execChain = execChain;
            this.connManager = connManager;
            this.routePlanner = routePlanner;
            this.cookieSpecRegistry = cookieSpecRegistry;
            this.authSchemeRegistry = authSchemeRegistry;
            this.cookieStore = cookieStore;
            this.credentialsProvider = credentialsProvider;
            this.defaultConfig = defaultConfig;
            this.closeables = closeables;
        }
    
        //......
    
        @Override
        public void close() {
            if (this.closeables != null) {
                for (final Closeable closeable: this.closeables) {
                    try {
                        closeable.close();
                    } catch (final IOException ex) {
                        this.log.error(ex.getMessage(), ex);
                    }
                }
            }
        }    
    }    
    

    InternalHttpClient继承了CloseableHttpClient,其构造器要求传入closeables,它实现了close方法,它主要是遍历closeables,挨个执行close

    HttpClientBuilder

    org/apache/http/impl/client/HttpClientBuilder.java

    public class HttpClientBuilder {
    
        private List<Closeable> closeables;
    
        private boolean connManagerShared;
    
        //......
    
        /**
         * For internal use.
         */
        protected void addCloseable(final Closeable closeable) {
            if (closeable == null) {
                return;
            }
            if (closeables == null) {
                closeables = new ArrayList<Closeable>();
            }
            closeables.add(closeable);
        }
    
        public CloseableHttpClient build() {
    
            //......
    
            List<Closeable> closeablesCopy = closeables != null ? new ArrayList<Closeable>(closeables) : null;
            if (!this.connManagerShared) {
                if (closeablesCopy == null) {
                    closeablesCopy = new ArrayList<Closeable>(1);
                }
                final HttpClientConnectionManager cm = connManagerCopy;
    
                if (evictExpiredConnections || evictIdleConnections) {
                    final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
                            maxIdleTime > 0 ? maxIdleTime : 10, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS,
                            maxIdleTime, maxIdleTimeUnit);
                    closeablesCopy.add(new Closeable() {
    
                        @Override
                        public void close() throws IOException {
                            connectionEvictor.shutdown();
                            try {
                                connectionEvictor.awaitTermination(1L, TimeUnit.SECONDS);
                            } catch (final InterruptedException interrupted) {
                                Thread.currentThread().interrupt();
                            }
                        }
    
                    });
                    connectionEvictor.start();
                }
                closeablesCopy.add(new Closeable() {
    
                    @Override
                    public void close() throws IOException {
                        cm.shutdown();
                    }
    
                });
            }
    
            //......
    
            return new InternalHttpClient(
                    execChain,
                    connManagerCopy,
                    routePlannerCopy,
                    cookieSpecRegistryCopy,
                    authSchemeRegistryCopy,
                    defaultCookieStore,
                    defaultCredentialsProvider,
                    defaultRequestConfig != null ? defaultRequestConfig : RequestConfig.DEFAULT,
                    closeablesCopy);
        }
    }    
    

    HttpClientBuilder定义了addCloseable方法用于添加closeable,不过是protected;而build方法在connManagerShared参数为false的时候(默认)会创建closeablesCopy,创建Closeable去关闭HttpClientConnectionManager并添加到closeablesCopy中;

    在开启evictExpiredConnections或者evictIdleConnections的时候会创建IdleConnectionEvictor,然后创建关闭connectionEvictor的Closeable添加到closeablesCopy中

    最后将这些closeablesCopy传递给InternalHttpClient的构造器

    小结

    HttpClient(CloseableHttpClient)的close方法会关闭一系列的Closeable,这些Closeable在HttpClientBuilder的build方法会构建好然后传递给InternalHttpClient;默认情况下这些closeable包括HttpClientConnectionManager的关闭、IdleConnectionEvictor的关闭。

    相关文章

      网友评论

          本文标题:聊聊HttpClient的close

          本文链接:https://www.haomeiwen.com/subject/epxyidtx.html