package com.junbo.salecard.service.yunxin.impl;
import com.winnerlook.service.https.MyVerifyHostname;
import com.winnerlook.service.https.MyX509TrustManager;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.entity.StringEntity;
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.pool.PoolStats;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author zsy
* @date 2022/1/14
*/
public class HttpClientUtils {
private static final Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
// 设定从连接池获取可用连接的时间
// private static final int connectPoolTimeout = 2000;
// 建立连接超时时间
// private static final int connectTimeout = 5000;
// 设置等待数据超时时间5秒钟 根据业务调整
// private static final int socketTimeout = 5000;
// 连接池最大连接数
// private static final int maxTotal = 100;
// 每个主机的并发
// private static final int maxPerRoute = 10;
// 目标主机的最大连接数
// private static final int maxRoute = 50;
private static CloseableHttpClient httpClient = null;
private final static Object SYNC_LOCK = new Object();
private static PoolingHttpClientConnectionManager cm = null;
private static final ScheduledExecutorService monitorExecutor;
private static boolean isShowUsePoolLog = true;
private static X509TrustManager tm;
static {
//org.apache.commons.lang3.concurrent.BasicThreadFactory
monitorExecutor = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("import-schedule-pool-%d").daemon(true).build());
}
/**
* 获取HttpClient对象
*
* @param url
* @return
* @author
* @date 2019年4月11日
*/
public static CloseableHttpClient getHttpClient(final String url) throws NoSuchAlgorithmException, KeyManagementException {
String hostname = url.split("/")[2];
int port = 80;
if (hostname.contains(":")) {
final String[] arr = hostname.split(":");
hostname = arr[0];
port = Integer.parseInt(arr[1]);
}
if (HttpClientUtils.httpClient == null) {
System.out.println("1****第一次创建httpClient");
// 多线程下多个线程同时调用getHttpClient容易导致重复创建httpClient对象的问题,所以加上了同步锁
synchronized (HttpClientUtils.SYNC_LOCK) {
if (HttpClientUtils.httpClient == null) {
int maxTotal = 10;
int maxPerRoute = 10;
int maxRoute = 10;
final long timeout = 1000;
System.out.println("2****第一次创建httpClient -->" + maxTotal);
// 开启监控线程,对异常和空闲线程进行关闭
HttpClientUtils.monitorExecutor.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
// 关闭异常连接
HttpClientUtils.cm.closeExpiredConnections();
// 关闭空闲的连接
HttpClientUtils.cm.closeIdleConnections(timeout, TimeUnit.MILLISECONDS);
final PoolStats poolStats = HttpClientUtils.cm.getTotalStats();
final int usePoolNum = poolStats.getAvailable() + poolStats.getLeased()
+ poolStats.getPending();
if (HttpClientUtils.isShowUsePoolLog) {
HttpClientUtils.logger.info("***********》关闭异常+空闲连接! 空闲连接:"
+ poolStats.getAvailable() + " 持久连接:" + poolStats.getLeased() + " 最大连接数:"
+ poolStats.getMax() + " 阻塞连接数:" + poolStats.getPending());
}
// if (usePoolNum == 0) {
// HttpClientUtils.isShowUsePoolLog = false;
// } else {
// HttpClientUtils.isShowUsePoolLog = true;
// }
HttpClientUtils.isShowUsePoolLog = usePoolNum != 0;
}
}, timeout, timeout, TimeUnit.MILLISECONDS);
HttpClientUtils.httpClient = HttpClientUtils.createHttpClient(maxTotal, maxPerRoute,
maxRoute, hostname, port);
}
}
} else {
System.out.println("3****获取已有的httpClient");
}
return HttpClientUtils.httpClient;
}
/**
* 创建HttpClient对象
*
* @param maxTotal 最大连接数
* @param maxPerRoute 每个主机的并发
* @param maxRoute 目标主机的最大并发,如果只有一台,可以和maxTotal一样
* @param hostname
* @param port
* @return
* @author
* @date 2019年4月11日
*/
private static CloseableHttpClient createHttpClient(
final int maxTotal,
final int maxPerRoute,
final int maxRoute,
final String hostname,
final int port) throws NoSuchAlgorithmException, KeyManagementException {
final ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
final LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", plainsf).register("https", sslsf).build();
HttpClientUtils.cm = new PoolingHttpClientConnectionManager(registry);
// 将最大连接数增加
HttpClientUtils.cm.setMaxTotal(maxTotal);
// 将每个路由基础的连接增加
HttpClientUtils.cm.setDefaultMaxPerRoute(maxPerRoute);
final HttpHost httpHost = new HttpHost(hostname, port);
// 将目标主机的最大连接数增加
HttpClientUtils.cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute);
// 请求重试处理
SSLContext sslContext = SSLContext.getInstance("TLS");
tm = new MyX509TrustManager();
sslContext.init(null, new TrustManager[]{tm},
new java.security.SecureRandom());
return HttpClients.custom()
.setConnectionManager(HttpClientUtils.cm)
.setSSLHostnameVerifier(new MyVerifyHostname())
.disableAutomaticRetries()
.setSSLContext(sslContext)
.build();
}
public static String doPost(String path, String headerStr,
String requestBody, String encoding) throws Exception {
String resultString;
CloseableHttpResponse response = null;
HttpPost httpPost = null;
try {
URI uri = new URI(path);
httpPost = new HttpPost(uri);
httpPost.setHeader("Content-type", "application/json; charset=utf-8");
/** 报文头中设置Authorization参数*/
httpPost.setHeader("Authorization", headerStr);
/** 设置请求报文体*/
httpPost.setEntity(new StringEntity(requestBody, encoding));
response = HttpClientUtils.getHttpClient(path).execute(httpPost);
HttpEntity httpEntity = response.getEntity();
httpEntity = new BufferedHttpEntity(httpEntity);
resultString = EntityUtils.toString(httpEntity);
} finally {
//释放连接
if (null != response) {
response.close();
}
// if (httpPost != null) {
// httpPost.releaseConnection();
// }
}
return resultString;
}
}
httpclient连接池
最新推荐文章于 2025-03-25 11:25:55 发布