今天在做腾讯网址安全检测API接入时用到了org.apache.httpcomponents.httpclient-4.5.5这个包,当初在main方法里测试的时候发现从请求到响应大概要用0.6s的时间,但是在springboot应用里面使用的时候,第一次请求用了0.4s左右,第二次就只要0.1s左右,很惊讶,然后想是不是连接池的作用,查找过程如下:
1.首先在本地,在将程序运行起来后先不进行请求,使用 jmap -histo:live 19144 > d://a.txt 命令(参考https://www.cnblogs.com/anjijiji/p/6239395.html)将JVM中存活的所有对象打印到文件中,在文件中查看是否存在org.apache.http开头包名的类,发现找不到。
2.使用postman进行一次API请求,然后在使用 jmap -histo:live 19144 > d://a.txt 将文件覆盖后进行查看,发现在文件中找到几个关于org.apache.http.impl.conn开头的几个类,将有关连接池的类列出如下:
org.apache.http.impl.conn.CPool
org.apache.http.impl.conn.CPoolEntry
org.apache.http.impl.conn.PoolingHttpClientConnectionManager
PoolingHttpClientConnectionManager是一个HttpClientConnection的连接池封装,可以为多线程提供并发请求服务。主要作用就是分配连接,回收连接等,同一个route的请求,会优先使用连接池提供的空闲长连接;CPoolEntry是ManagedHttpClientConnection的封装,包含具体的一个连接的信息;CPool是继承AbstractConnPool的一个连接池实现,PoolingHttpClientConnectionManager在进行具体的分配连接,回收连接获时实际上调用的是CPool。
只介绍cpool几个属性(供参考):
routeToPool: 具体的路由粒度对应的连接池
leased: 已经被租用的连接(正在被使用的)
available: 空闲连接
pending: 正在等待获取连接队列
maxPerRoute: 每个路由上最大的连接数(不能超过连接池总连接数)
defaultMaxPerRoute: 默认的每个路由上最大的连接数(不能超过连接池总连接数)
maxTotal: 连接池最大的连接数
validateAfterInactivity:空闲永久连接检查间隔,这个牵扯的还比较多官方推荐使用这个来检查永久链接的可用性,而不推荐每次请求的时候才去检查(ms)
3.在知道以上的原理之后,下面列出具体配置代码(欢迎指出错误和共同交流!)
public class UrlUtil { public static final Logger logger = LoggerFactory.getLogger(UrlUtil.class); private static CloseableHttpClient httpClient = null;// static { PoolingHttpClientConnectionManager clientConnectionManager = new PoolingHttpClientConnectionManager(); clientConnectionManager.setValidateAfterInactivity(2000);//检测有效连接的间隔 clientConnectionManager.setMaxTotal(50);//设定连接池最大数量 clientConnectionManager.setDefaultMaxPerRoute(50);//设定默认单个路由的最大连接数(由于本处只使用一个路由地址所以设定为连接池大小) httpClient = HttpClients.createMinimal(clientConnectionManager); } /** * 检测URL安全,腾讯网址安全API(部分代码) * @param urlString * @return * @throws Exception */ public static void urlSafe(String urlString) throws Exception { CloseableHttpResponse response = null; try { HttpPost httpPost = new HttpPost("http://www.cloud.urlsec.qq.com"); RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(1000)//设定连接服务器超时时间 .setConnectTimeout(1000)//设定从连接池获取可用连接的时间 .setSocketTimeout(1000)//设定获取数据的超时时间 .build(); httpPost.setConfig(requestConfig); HttpEntity entity = new StringEntity(params,"utf-8"); httpPost.setEntity(entity); httpPost.setHeader("Content-type", "application/json"); response = httpClient.execute(httpPost); } catch (Exception e) { throw e; }finally { if (null != response) { response.close(); } } } }
参考文章:https://www.cnblogs.com/shoren/p/httpclient-leaseConnection.html