HttpClient连接池

Posted xiaolei2017

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HttpClient连接池相关的知识,希望对你有一定的参考价值。

package cn.com.cfets.imt.impl.spring.util;

import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Map;

/**
 * 连接池
 * Created by fenglei.ma on 2018/5/23. 17:54
 */
public class HttpClientUtils {

    private static final Logger log = LoggerFactory.getLogger(HttpClientUtils.class);

    public static int CONNECT_TIME = 3 * 1000;
    public static int SOCKET_TIME  = 3 * 1000; // 毫秒
    public static int REQUEST_TIME = 3 * 1000;

    // 是否重连
    public static String ISRECONN = "N";


    // 这里使用连接池防止高并发大量请求时来提高吞吐量
    public static PoolingHttpClientConnectionManager cm = null;
    // 使用默认的httpClient实例.
    public static CloseableHttpClient httpClient = null;

    // 每个route最大连接数
    private static final int count = 32;
    // 整个连接池的最大连接数
    private static final int totalCount = 500;
    private static final int Http_Default_Keep_Time =15000;


    public static synchronized void initPools() {
        if (httpClient == null) {
            cm = new PoolingHttpClientConnectionManager();
            cm.setDefaultMaxPerRoute(count);
            cm.setMaxTotal(totalCount);

            // 禁用重定向  setRedirectsEnabled(Boolean.FALSE)
            if("Y".equalsIgnoreCase(ISRECONN)){
                httpClient = HttpClients.custom().setDefaultRequestConfig(
                        RequestConfig.custom().setRedirectsEnabled(Boolean.FALSE).build()
                ).setKeepAliveStrategy(defaultStrategy).setConnectionManager(cm).build();
            }else if("N".equalsIgnoreCase(ISRECONN) || StringUtils.isEmpty(ISRECONN)){
                /**
                 * automaticRetriesDisabled类型是boolean,默认值是false,
                 * 这里设置为true,禁止重试连接3次
                 */
                httpClient = HttpClients.custom().setDefaultRequestConfig(
                        RequestConfig.custom().setRedirectsEnabled(Boolean.FALSE).build()
                ).setKeepAliveStrategy(defaultStrategy).setConnectionManager(cm).disableAutomaticRetries().build();
            }
        }
    }


    /**
     * 配置请求的超时设置
     * @param httpRequestBase
     */
    private static void config(HttpRequestBase httpRequestBase) {
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(REQUEST_TIME)
                .setConnectTimeout(CONNECT_TIME).setSocketTimeout(SOCKET_TIME).build();
        httpRequestBase.setConfig(requestConfig);
    }

    /**
     * Http connection keepAlive 设置
     */
    public static ConnectionKeepAliveStrategy defaultStrategy = new ConnectionKeepAliveStrategy() {
        public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
            HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
            int keepTime = Http_Default_Keep_Time;
            while (it.hasNext()) {
                HeaderElement he = it.nextElement();
                String param = he.getName();
                String value = he.getValue();
                if (value != null && param.equalsIgnoreCase("timeout")) {
                    try {
                        return Long.parseLong(value) * 1000;
                    } catch (Exception e) {
                        log.error("format KeepAlive timeout exception, exception:" + e.toString());
                    }
                }
            }
            return keepTime * 1000;
        }
    };


    /**
     * Get 请求
     * @param path 请求url
     * @param jsonParam 请求参数
     * @param allHeader 请求头
     * @return
     */
    public static HttpResponse executeGetMothedRequest(String path, String jsonParam, Map<String, String> allHeader) {
        HttpGet httpget = null;
        HttpResponse response = null;
        try {
            if (!StringUtils.isEmpty(jsonParam)) {
                path = path + "?" + jsonParam;
                log.info(path);
            }

            URL url = new URL(path);
            URI uri = new URI(url.getProtocol(), null, url.getHost(), url.getPort(), url.getPath(), url.getQuery(), null);
            httpget = new HttpGet(uri);

            httpget.setHeader("Content-Type", "application/json");
            for (Map.Entry<String, String> e : allHeader.entrySet()) {
                httpget.setHeader(e.getKey(), e.getValue());
            }

            if(httpClient == null){
                initPools();
            }
            config(httpget);

            response = httpClient.execute(httpget);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return response;
    }


    /**
     * Post 请求
     * @param url 请求url
     * @param body  请求数据
     * @param paramJson 请求参数
     * @param allHeade 请求消息头
     * @return
     */
    public static HttpResponse executePostMothedRequest(String url, byte[] body, String paramJson, Map<String, String> allHeade) {
        HttpPost httppost = null;
        HttpResponse response = null;
        try {
            if (!StringUtils.isEmpty(paramJson)) {
                url = url + "?" + paramJson;
                log.info(url);
            }

            httppost = new HttpPost(url);

            // 消息头
            for (Map.Entry<String, String> e : allHeade.entrySet()) {
//                httppost.setHeader("Content-Type", "application/json");
                httppost.setHeader(e.getKey(), e.getValue());
            }

            // 包含上传文件数据
            if (!StringUtils.isEmpty(body)) {
//                httppost.setHeader("Content-Type", "application/json");
                httppost.setEntity(new ByteArrayEntity(body));
            }

            if(httpClient == null){
                initPools();
            }
            config(httppost);

            response = httpClient.execute(httppost);
            if (response.getStatusLine().getStatusCode() >= 400) {
                log.warn("Failed : HTTP error code :" + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return response;
    }


}

 

以上是关于HttpClient连接池的主要内容,如果未能解决你的问题,请参考以下文章

HttpClient连接池

HttpClient连接池的一些思考

总结httpclient资源释放和连接复用

使用 HttpClient 的 HTTP 连接池

RestTemplate使用HttpClient连接池

HttpComponents HttpClient连接池-结构