HttpClient连接池小记 我不是女神ヾ 2021-11-09 20:20 359阅读 0赞 \*\*欢迎关注公众号\*\* ![20191121223121694.jpg][] \*\*微信扫一扫\*\* **【仅需9.9订阅[专栏合集][Link 1],作者所有付费文章都能看(持续更新)】** 推荐【**Kafka教程**】[https://bigbird.blog.csdn.net/article/details/108770504][https_bigbird.blog.csdn.net_article_details_108770504] 推荐【**rabbitmq教程**】[https://bigbird.blog.csdn.net/article/details/81436980][https_bigbird.blog.csdn.net_article_details_81436980] 推荐【**Flink教程**】[https://blog.csdn.net/hellozpc/article/details/109413465][https_blog.csdn.net_hellozpc_article_details_109413465] 推荐【**JVM面试与调优教程**】[https://bigbird.blog.csdn.net/article/details/113888604][https_bigbird.blog.csdn.net_article_details_113888604] 推荐【**SpringBoot全套教程**】[https://blog.csdn.net/hellozpc/article/details/107095951][https_blog.csdn.net_hellozpc_article_details_107095951] 推荐【**SpringCloud教程**】[https://blog.csdn.net/hellozpc/article/details/83692496][https_blog.csdn.net_hellozpc_article_details_83692496] 推荐【**Mybatis教程**】[https://blog.csdn.net/hellozpc/article/details/80878563][https_blog.csdn.net_hellozpc_article_details_80878563] 推荐【**SnowFlake教程**】[https://blog.csdn.net/hellozpc/article/details/108248227][https_blog.csdn.net_hellozpc_article_details_108248227] 推荐【**并发限流教程**】[https://blog.csdn.net/hellozpc/article/details/107582771][https_blog.csdn.net_hellozpc_article_details_107582771] 推荐【**Redis教程**】[https://bigbird.blog.csdn.net/article/details/81267030][https_bigbird.blog.csdn.net_article_details_81267030] 推荐【**Netty教程**】[https://blog.csdn.net/hellozpc/category\_10945233.html][https_blog.csdn.net_hellozpc_category_10945233.html] 推荐**Springboot集成http连接池** [https://blog.csdn.net/hellozpc/article/details/106861972][https_blog.csdn.net_hellozpc_article_details_106861972] * 常用的http客户端有JDK原生的URLConnection、Netty的异步HTTP Client、Spring的RestTemplate、Spring Cloud中的Feign。 虽然RestTemplate、Feign使用极其方便,但是屏蔽了太多底层细节,不利于全局把控。 * 本文主要记载一下基于Apache **HttpClient** 的http **连接池**处理。网上很多文章都没有关注定期检测关闭无效连接这块功能。另外要注册jvm钩子在程序退出时关闭httpClient实例。 /** * 业务层调用HttpTemplate#execute发送http post请求 * @author zhoupengcheng */ public class HttpTemplate { private static Logger logger = LoggerFactory.getLogger(HttpTemplate.class); private static final String DEFAULT_ACCEPTTYPE = "application/json;charset=utf-8"; private static final String DEFAULT_CHARSET = "utf-8"; /** * 最大连接数 */ private static final int MAX_CONNECTION_NUM = 20; /** * 单路由最大连接数 */ private static final int MAX_PER_ROUTE = 20; /** * 连接超时时间,缺省为3秒钟 */ private static final int DEFAULT_CONNECTION_TIMEOUT = 3000; /** * 读取超时时间,缺省为3秒钟 */ private static final int DEFAULT_READ_TIMEOUT = 3000; /** * 连接池管理对象 */ private PoolingHttpClientConnectionManager cm; private CloseableHttpClient httpClient; /** * 反序列化工具 */ private ObjectMapper objectMapper; public HttpTemplate() { init(); } public void init() { initObjectMapper(); initHttpClient(); } private void initHttpClient() { HttpClientBuilder builder = HttpClients.custom(); builder.disableCookieManagement(); builder.disableRedirectHandling(); builder.disableAutomaticRetries(); builder.setConnectionManagerShared(false) .evictIdleConnections(1, TimeUnit.MINUTES)// 定期回收空闲连接 .evictExpiredConnections()// 定期回收过期连接 .setConnectionTimeToLive(1, TimeUnit.MINUTES) // 连接存活时间,如果不设置,则根据长连接信息决定 .setDefaultRequestConfig( RequestConfig .custom() .setAuthenticationEnabled(false) .setCircularRedirectsAllowed(false) .setSocketTimeout(DEFAULT_READ_TIMEOUT) .setConnectTimeout(DEFAULT_CONNECTION_TIMEOUT) .setConnectionRequestTimeout(1000) .setCookieSpec(CookieSpecs.IGNORE_COOKIES) .build()) // 设置默认请求配置 .setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE) // 连接重用策略 是否能keepAlive .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)// 长连接配置,即获取长连接生产多长时间 .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))// 重试次数 默认3次 此处禁用 .build(); Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("https", PlainConnectionSocketFactory.getSocketFactory()) .register("http", new PlainConnectionSocketFactory()).build(); final int conExpire = 15;// 长连接闲置过期时间,可配置 cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry, null, null, null, conExpire, TimeUnit.SECONDS); cm.setDefaultConnectionConfig(ConnectionConfig.DEFAULT); cm.setMaxTotal(MAX_CONNECTION_NUM); cm.setDefaultMaxPerRoute(MAX_PER_ROUTE); // 设置长连接心跳检测,设置超时,禁用nagle算法 cm.setDefaultSocketConfig(SocketConfig.custom().setSoKeepAlive(true).setSoTimeout(DEFAULT_READ_TIMEOUT).setTcpNoDelay(true).build()); cm.setValidateAfterInactivity(-1);// 每次取重用的连接时禁止连接活性检测,可以提升性能 builder.setConnectionManager(cm); builder.setConnectionManagerShared(false); httpClient = builder.build(); // 过期检测 Thread staleCheckThread = new Thread(() -> { while (true) { try { Thread.sleep(10000); cm.closeExpiredConnections(); cm.closeIdleConnections(conExpire, TimeUnit.SECONDS); } catch (Exception e) { logger.error("stale check exception", e); } } }, "HttpInvoker-coonection-stale-check-thread"); // 设置成为守护线程 staleCheckThread.setDaemon(true); staleCheckThread.start(); // 程序退出时,关闭httpClient Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { httpClient.close(); logger.info(">>>>httpClient closed<<<<"); } catch (Exception e) { logger.warn("httpClient close exception", e); } }, "srsynchronize-httpInvoker-shutdown-thread")); } private void initObjectMapper() { objectMapper = new ObjectMapper(); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); } /** * 暴露给业务层调用的方法 * @param path 请求url * @param req 请求对象 * @param typeReference 响应对象 * @param <R> * @return * @throws Exception */ public <R extends Response> R execute(String path, Object req, TypeReference<R> typeReference) throws Exception { if (typeReference == null) { typeReference = (TypeReference<R>) new TypeReference<Response>() { }; } String reqBody = objectMapper.writeValueAsString(req); logger.info("reqBody:{}", reqBody); HttpPost httpPost = new HttpPost(path); httpPost.setProtocolVersion(HttpVersion.HTTP_1_1); httpPost.setHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_KEEP_ALIVE); httpPost.setConfig(RequestConfig.custom().setSocketTimeout(DEFAULT_READ_TIMEOUT) .setConnectTimeout(DEFAULT_CONNECTION_TIMEOUT).build()); httpPost.addHeader("Accept", DEFAULT_ACCEPTTYPE); httpPost.addHeader("Content-Type", DEFAULT_ACCEPTTYPE); HttpEntity httpEntity = new StringEntity(reqBody, DEFAULT_CHARSET); httpPost.setEntity(httpEntity); CloseableHttpResponse httpResponse = httpClient.execute(httpPost); String responseBody = EntityUtils.toString(httpResponse.getEntity(), DEFAULT_CHARSET); logger.info("resBody:{}", responseBody); return objectMapper.readValue(responseBody, typeReference); } /** * demo * * @param args * @throws Exception */ public static void main(String[] args) throws Exception { HttpTemplate httpTemplate = new HttpTemplate(); Order order = new Order(); order.id = "1111111"; order.cancleRemarks = "擦擦擦"; order.createDate = LocalDateTime.now(); order.startLongitude = "1356.4343"; OrderResponse orderResponse = httpTemplate.execute("http://127.0.0.1:8888/ordersdispatch", order, new TypeReference<OrderResponse>() { }); //不传具体的OrderResponse会使用默认的Response Response response = httpTemplate.execute("http://127.0.0.1:8888/orderdispatch", order, null); logger.info("orderResponse:{}", orderResponse); logger.info("response:{}", response); } } public class Order { public String id; public String orderCode; public String startCityName; public String startAddress; public String startAddDtl; public String startLongitude; public String startLatitude; public String endCityName; public String endAddress; public String endAddDtl; public String endLongitude; public String endLatitude; public byte prodType; public LocalDateTime orderDate; public int orderDay; public String flightNo; public String remark; public int orderState; public String driverId; public String driverUid; public String driverMobile; public String source; public LocalDateTime createDate; public LocalDateTime updateDate; public String dispatchType; public String driverRemark; public LocalDateTime flightDate; public String flightArrCode; public String flightDepCode; public String cancleRemarks; public LocalDateTime endTime; } /** * http响应实体 */ public class Response { public static int SUCCESS_CODE = 0; public Integer retCode; public String retMsg; public static boolean isSuccess(Response res) { return res != null && res.retCode == SUCCESS_CODE; } @Override public String toString() { return "Response{" + "retCode=" + retCode + ", retMsg='" + retMsg + '\'' + '}'; } } public class OrderResponse extends Response { public List<Order> info; } \*\*欢迎关注公众号\*\* ![20191121223121694.jpg][] \*\*微信扫一扫\*\* [20191121223121694.jpg]: /images/20211109/9dadc1b63a8c4d9ca7556c9e358ba0a3.png [Link 1]: https://blog.csdn.net/hellozpc/category_11127579.html [https_bigbird.blog.csdn.net_article_details_108770504]: https://bigbird.blog.csdn.net/article/details/108770504 [https_bigbird.blog.csdn.net_article_details_81436980]: https://bigbird.blog.csdn.net/article/details/81436980 [https_blog.csdn.net_hellozpc_article_details_109413465]: https://blog.csdn.net/hellozpc/article/details/109413465 [https_bigbird.blog.csdn.net_article_details_113888604]: https://bigbird.blog.csdn.net/article/details/113888604 [https_blog.csdn.net_hellozpc_article_details_107095951]: https://blog.csdn.net/hellozpc/article/details/107095951 [https_blog.csdn.net_hellozpc_article_details_83692496]: https://blog.csdn.net/hellozpc/article/details/83692496 [https_blog.csdn.net_hellozpc_article_details_80878563]: https://blog.csdn.net/hellozpc/article/details/80878563 [https_blog.csdn.net_hellozpc_article_details_108248227]: https://blog.csdn.net/hellozpc/article/details/108248227 [https_blog.csdn.net_hellozpc_article_details_107582771]: https://blog.csdn.net/hellozpc/article/details/107582771 [https_bigbird.blog.csdn.net_article_details_81267030]: https://bigbird.blog.csdn.net/article/details/81267030 [https_blog.csdn.net_hellozpc_category_10945233.html]: https://blog.csdn.net/hellozpc/category_10945233.html [https_blog.csdn.net_hellozpc_article_details_106861972]: https://blog.csdn.net/hellozpc/article/details/106861972
还没有评论,来说两句吧...