如何在httpclient4.5.4中发布PoolingHttpClientConnectionManager

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在httpclient4.5.4中发布PoolingHttpClientConnectionManager相关的知识,希望对你有一定的参考价值。

我在使用httpclients 4.5.4时遇到了问题。当我关闭与我的连接相关的所有内容时,java GC无法收集PoolingHttpClientConnectionManager对象。因此,当应用程序运行大约1个月时,我遇到了一个OOM异常。我的代码与https://hc.apache.org/httpcomponents-client-4.5.x/httpclient/examples/org/apache/http/examples/client/ClientConnectionRelease.java中的示例相同。并且Java GC也无法收集InternalHttpClient对象。下面有我的代码,是否有任何对象持有这两个类的引用?

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.Map;

    import org.apache.http.HttpStatus;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.ContentType;
    import org.apache.http.entity.mime.MultipartEntityBuilder;
    import org.apache.http.entity.mime.content.FileBody;
    import org.apache.http.entity.mime.content.StringBody;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    public class HttpUtil {

        private static Logger logger = LoggerFactory.getLogger(HttpUtil.class);

        /**
         * Http post请求
         */
        public static String doHttpPost(String postUrl, Map<String, String> headers,
                Map<String,String> params,String filePath) {
            try {
                CloseableHttpClient httpClient = HttpClients.createDefault();
                try {
                    HttpPost post = getHttpPost(postUrl, headers, params, filePath);
                    CloseableHttpResponse response = httpClient.execute(post);
                    try {
                        InputStream inputStream = null;
                        InputStreamReader inputStreamReader = null;
                        BufferedReader bufferedReader = null;
                        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                            try {
                                inputStream = response.getEntity().getContent();
                                inputStreamReader = new InputStreamReader(inputStream);
                                bufferedReader = new BufferedReader(inputStreamReader);
                                return bufferedReader.readLine();
                            }catch (Exception e) {
                                logger.warn("do http post fail : ", e);
                            }finally {
                                if (bufferedReader != null) {
                                    logger.info("release bufferedReader: " + filePath);
                                    bufferedReader.close();
                                }
                                if (inputStreamReader != null) {
                                    logger.info("release inputStreamReader: " +filePath);
                                    inputStreamReader.close();
                                }
                                if (inputStream != null) {
                                    logger.info("release inputStream: " +filePath);
                                    inputStream.close();
                                }
                            }
                        }
                    } catch (Exception e) {
                        logger.warn("do http post fail: ", e);
                    } finally {
                        if (response != null) {
                            logger.info("release response: " + filePath);
                            response.close();
                        }
                        if (post != null) {
                            logger.info("release HttpPost: " + filePath);
                            post.releaseConnection();
                        }
                    }
                } catch (Exception e) {
                    logger.warn("do http post fail: ", e);
                } finally {
                    if (httpClient != null) {
                        logger.info("release httpClient: " + filePath);
                        httpClient.close();
                        logger.info("release connectionManager: " + filePath);
                        httpClient.getConnectionManager().shutdown();
                    }
                }
            } catch (Exception e) {
                logger.warn("do http post fail: ", e);
            }

            return "";
        }

        private static HttpPost getHttpPost(String postUrl, Map<String, String> headers,
                Map<String, String> params, String filePath) {
            HttpPost post = new HttpPost(postUrl);
            String[] headerKeys = headers.keySet().toArray(new String[headers.keySet().size()]);
            for (String key : headerKeys) {
                post.setHeader(key, headers.get(key));
            }

            FileBody fileBody = new FileBody(new File(filePath));
            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
            multipartEntityBuilder.addPart("express_image", fileBody);

            String[] paramKeys = params.keySet().toArray(new String[params.keySet().size()]);
            for (String key : paramKeys) {
                StringBody valueBody = new StringBody(params.get(key), ContentType.TEXT_PLAIN);
                multipartEntityBuilder.addPart(key, valueBody);
            }

            post.setEntity(multipartEntityBuilder.build());
            return post;
        }

    }
答案

我不能告诉你为什么你的内存耗尽,但我可以告诉你,以这种方式做到这一点并不是一个好主意(尽管你使用的是“推荐方式”)。

我正在使用版本4.5.3中的CloseableHttpClientPoolingHttpClientConnectionManager而且我从不关闭它们(它们都在单例中分配一次并用于所有请求)。我的应用程序目前运行,因为可能一个月每秒做一个请求(不是很多)。

请注意,为每个连接创建新客户端与为每次旅行购买新车一样高效。

以上是关于如何在httpclient4.5.4中发布PoolingHttpClientConnectionManager的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中使用 multiprocessing.pool 创建全局锁/信号量?

如何在 Laravel 中测试 Http Pool?

多处理:如何在类中定义的函数上使用 Pool.map?

如何从 pool.apply_async 调用中累积结果?

如何使用 Python 多处理 Pool.map 在 for 循环中填充 numpy 数组

从多处理中使用Pool时如何获取函数中的进程号