1.2.1. HttpClient thread safety
HttpClient
implementations are expected to be thread safe. It is recommended that the same instance of this class is reused for multiple request executions.
由官方文档可知,HttpClient 是线程安全的,建议使用同一实例。
因此使用单例模式创建,优化反复创建的开销。
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
// Increase max total connection to 200
cm.setMaxTotal(200);
// Increase default max connection per route to 20
cm.setDefaultMaxPerRoute(20);
// Increase max connections for localhost:80 to 50
HttpHost localhost = new HttpHost("locahost", 80);
cm.setMaxPerRoute(new HttpRoute(localhost), 50);
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.build();
是否使用keep-alive要根据业务情况来定
在本业务场景里,我们相当于有少数固定客户端,长时间高频次的访问服务器,启用keep-alive非常合适
ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
// Honor 'keep-alive' header
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
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(NumberFormatException ignore) {
}
}
}
HttpHost target = (HttpHost) context.getAttribute(
HttpClientContext.HTTP_TARGET_HOST);
if ("www.naughty-server.com".equalsIgnoreCase(target.getHostName())) {
// Keep alive for 5 seconds only
return 5 * 1000;
} else {
// otherwise keep alive for 30 seconds
return 30 * 1000;
}
}
};
CloseableHttpClient client = HttpClients.custom()
.setKeepAliveStrategy(myStrategy)
.build();
manager为 Pooling connection manager
// 开启监控线程,对异常和空闲线程进行关闭
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
executorService.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
// 关闭异常连接
manager.closeExpiredConnections();
// 关闭30s空闲的连接
manager.closeIdleConnections(30, TimeUnit.MILLISECONDS);
// log.info("close expired and idle for over 30s connection");
}
}, 30, 5, TimeUnit.SECONDS);