HttpClient连接池管理

@Configuration
@EnableConfigurationProperties(HttpClientProperties.class)
@ConditionalOnProperty(prefix = "myserver.httpclient", value = "enabled", havingValue = "true")
public class HttpClientConfig {

    @Autowired
    HttpClientProperties httpClientProperties;

    @Bean
    PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {
        PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager();
        pool.setDefaultMaxPerRoute(httpClientProperties.getDefaultMaxPerRoute());
        pool.setMaxTotal(httpClientProperties.getMaxTotal());
        //官方同时建议我们在后台起一个定时清理无效连接的线程,
        new HttpClientPoolIdleConnectionMonitorThread(pool, httpClientProperties).start();
        return pool;
    }

    @Bean
    HttpClientBuilder httpClientBuilder(PoolingHttpClientConnectionManager poolingHttpClientConnectionManager) {
        HttpClientBuilder builder = HttpClientBuilder.create();
        builder.setConnectionManager(poolingHttpClientConnectionManager);
        return builder;
    }

    @Bean
    CloseableHttpClient getHttpClient(HttpClientBuilder httpClientBuilder) {
        CloseableHttpClient httpClient = httpClientBuilder.build();
        return httpClient;
    }

    @Bean
    HttpUtils getHttpUtils(CloseableHttpClient httpClient) {
        if (!httpClientProperties.getPool()) {
            httpClient = HttpClients.createDefault();
        }
        HttpUtils httpUtils = new HttpUtils(httpClient, httpClientProperties.getPool());
        return httpUtils;
    }


}
/**
 * <p>
 * Title:HttpClientPoolIdleConnectionMonitorThread
 * <p>
 * Description:官方同时建议我们在后台起一个定时清理无效连接的线程,
 * <p>
 * 因为某些连接建立后可能由于服务端单方面断开连接导致一个不可用的连接一直占用着资源,
 * <p>
 * 而HttpClient框架又不能百分之百保证检测到这种异常连接并做清理
 * <p>
 * Date: 2019-07-12 21:23
 *
 * @author 
 */
public class HttpClientPoolIdleConnectionMonitorThread extends Thread {

    private final HttpClientConnectionManager connMgr;
    private volatile boolean shutdown;
    private HttpClientProperties httpClientProperties;

    public HttpClientPoolIdleConnectionMonitorThread(HttpClientConnectionManager connMgr, HttpClientProperties httpClientProperties) {
        super();
        this.connMgr = connMgr;
        this.httpClientProperties = httpClientProperties;
    }

    @Override
    public void run() {
        try {
            while (!shutdown) {
                synchronized (this) {
                    wait(httpClientProperties.getPoolIdleConnectionMonitor().getWaitTime());
                    // Close expired connections
                    connMgr.closeExpiredConnections();
                    // Optionally, close connections
                    // that have been idle longer than 30 sec
                    connMgr.closeIdleConnections(httpClientProperties.getPoolIdleConnectionMonitor().getCloseIdleTime(), TimeUnit.SECONDS);
                }
            }
        } catch (InterruptedException ex) {
            // terminate
        }
    }

    public void shutdown() {
        shutdown = true;
        synchronized (this) {
            notifyAll();
        }
    }
}
@Log4j2
@Data
public class HttpUtils {

    private static final int HTTPCLIENT_TIMEOUT = 60000;
    private static Charset DEFAULT_UTF8 = StandardCharsets.UTF_8;
    /**
     * 若为连接池 isPool设置为true
     */
    private CloseableHttpClient httpClient;
    /**
     * httpClient 是否为连接池
     */
    private boolean isPool;

    public HttpUtils() {
        this(HttpClients.createDefault(), false);
    }

    public HttpUtils(CloseableHttpClient httpClient, boolean isPool) {
        super();
        this.httpClient = httpClient;
        this.isPool = isPool;
    }


    public BiStringEntry post(String sendURL, Map<String, String> params) {
        if (!this.isPool) {
            this.httpClient = HttpClients.createDefault();
        }
        return post(sendURL, getNameValueList(params), DEFAULT_UTF8, null);
    }


    public BiStringEntry post(String sendURL, String entityContent) {
        return post(sendURL, new StringEntity(entityContent, DEFAULT_UTF8));
    }

    public BiStringEntry post(String sendURL, List<NameValuePair> nameValueList, Charset encoding, String
            contentType) {
        return post(sendURL, getUrlEncoded(nameValueList, encoding, contentType));
    }


    public BiStringEntry post(String sendURL, HttpEntity httpEntity) {

        BiStringEntry result = new BiStringEntry(BiStringEntry.ERROR, "");

        Long longTime = System.currentTimeMillis();
        result.setExt(longTime);


        CloseableHttpResponse response = null;
        HttpPost httpPost = null;
        HttpEntity respEntity = null;
        try {

            httpPost = new HttpPost(sendURL);
            httpPost.setHeader(HttpHeaders.ACCEPT_LANGUAGE, "zh-cn");

            RequestConfig config = RequestConfig.custom().setSocketTimeout(HTTPCLIENT_TIMEOUT)
                    .setConnectionRequestTimeout(HTTPCLIENT_TIMEOUT).setConnectTimeout(HTTPCLIENT_TIMEOUT).build();
            httpPost.setConfig(config);
            httpPost.setEntity(httpEntity);


            response = httpClient.execute(httpPost);
            if (response == null) {
                return result;
            }

            Integer respStatus = response.getStatusLine().getStatusCode();

            try {

                if (HttpStatus.SC_OK == respStatus) {

                    result.setCode(BiStringEntry.SUCCESS);
                    respEntity = response.getEntity();
                    if (respEntity != null) {
                        String msg = EntityUtils.toString(respEntity, DEFAULT_UTF8);
                        result.setMsg(msg);
                    }
                } else {
                    result.put(BiStringEntry.ERROR, response.getStatusLine().toString());
                }

            } finally {
                if (respEntity != null) {
                    EntityUtils.consume(respEntity);
                }
                try {
                    response.close();
                } catch (IOException e) {
                    log.error("HttpUtils response exception", e);
                }
            }

        } catch (Exception e) {
            log.error("HttpUtils exception", e);
            // 异常返回
            result.put(BiStringEntry.ERROR, e.getMessage());
        } finally {
        	if (null != httpPost) {
				httpPost.releaseConnection();
				httpPost = null;
			}
            if (!isPool) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    log.error("HttpUtils close exception", e);
                }
            }
        }

        return result;

    }


    /**
     * <p>
     * Title: getNameValueList
     *
     * @param params
     * @return List<NameValuePair> 返回类型
     */
    public static List<NameValuePair> getNameValueList(Map<String, String> params) {

        List<NameValuePair> result = new ArrayList<NameValuePair>();

        if (null != params && !params.isEmpty()) {

            Set<Map.Entry<String, String>> paramsSet = params.entrySet();

            for (Map.Entry<String, String> entry : paramsSet) {
                result.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }
        return result;
    }

    /**
     * <p>
     * Title: UrlEncodedFormEntity
     *
     * @param nvps        nvps
     * @param encoding    encoding
     * @param contentType contentType
     * @return UrlEncodedFormEntity 返回类型
     */
    private static UrlEncodedFormEntity getUrlEncoded(List<NameValuePair> nvps, Charset encoding, String
            contentType) {

        if (nvps == null) {
            nvps = new ArrayList<>();
        }

        UrlEncodedFormEntity result = new UrlEncodedFormEntity(nvps, encoding);
        if (null != contentType && !contentType.isEmpty()) {
            result.setContentType(contentType);
        }
        return result;
    }

}

@Data
@ConfigurationProperties(prefix = "myserver.httpclient.poolmanager")
public class HttpClientProperties {

    // 1、MaxtTotal是整个池子的大小;
    // 2、DefaultMaxPerRoute是根据连接到的主机对MaxTotal的一个细分;比如:
    // MaxtTotal=400 DefaultMaxPerRoute=200
    // 而我只连接到http://a.com时,到这个主机的并发最多只有200;而不是400;
    // 而我连接到http://a.com 和 http://b.com时,到每个主机的并发最多只有200;即加起来是400(但不能超过400);
    // 所以起作用的设置是DefaultMaxPerRoute。

    /**
     * 将最大连接数增加到400
     */
    private Integer maxTotal = 400;
    /**
     * 将每个路由基础的连接增加到200
     */
    private Integer defaultMaxPerRoute = 20;
    /**
     * 是否线程池
     */
    private Boolean pool = true;
    /**
     * 官方同时建议我们在后台起一个定时清理无效连接的线程
     */
    private PoolIdleConnectionMonitor poolIdleConnectionMonitor;


    @Data
    public static class PoolIdleConnectionMonitor {
        /**
         * 等待时间
         */
        private Integer waitTime = 5000;
        /**
         * Optionally, close connections
         * that have been idle longer than 30 sec
         */
        private Integer closeIdleTime = 30;

    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值