在Tomcat8部署Spring Boot时,未关闭CloseableHttpClient有何影响?
这个问题我之前也碰到过,虽然是低流量的旧代码,但资源泄漏的坑绝对不能踩——哪怕现在没出问题,哪天流量上来或者Tomcat资源吃紧的时候,麻烦就来了。
为什么必须关闭CloseableHttpClient和CloseableHttpResponse?
首先得明确:这两个类都实现了AutoCloseable接口,意味着它们持有底层的网络连接、socket等系统资源。如果不主动关闭,这些资源不会被及时释放,会一直占用连接池或者系统句柄。哪怕是低流量场景,长期积累下来也可能导致连接耗尽,Tomcat容器的资源是有限的,到时候就会出现请求超时、服务不可用的情况。
至于官方快速入门示例没写关闭,大概率是为了简化示例、突出核心功能,绝对不能直接照搬进生产代码。
修复方案推荐
方案1:使用try-with-resources(最规范)
Java 7引入的try-with-resources语法是处理可关闭资源的最优解,它会自动帮你关闭实现了AutoCloseable的资源,不用手动写finally,代码还更简洁:
try (CloseableHttpClient httpClient = HttpClients.custom().build(); CloseableHttpResponse response = httpClient.execute(target, post)) { // 这里写你的response处理逻辑,比如获取实体、解析内容等 HttpEntity entity = response.getEntity(); if (entity != null) { // 额外提醒:如果使用EntityUtils处理实体,记得调用consume释放资源 EntityUtils.consume(entity); } } catch (IOException e) { // 异常处理,比如打日志、抛出业务异常等 log.error("HTTP请求执行失败", e); }
方案2:手动加finally块(兼容旧代码结构)
如果因为旧代码结构限制,暂时没法用try-with-resources,那一定要手动加finally块关闭资源,注意要分别处理每个资源的关闭,避免空指针和异常掩盖:
CloseableHttpClient httpClient = HttpClients.custom().build(); CloseableHttpResponse response = null; try { response = httpClient.execute(target, post); // 处理response逻辑 HttpEntity entity = response.getEntity(); if (entity != null) { EntityUtils.consume(entity); } } catch (IOException e) { log.error("HTTP请求出错", e); } finally { // 先关闭response if (response != null) { try { response.close(); } catch (IOException e) { log.warn("关闭HttpResponse失败", e); } } // 再关闭httpClient if (httpClient != null) { try { httpClient.close(); } catch (IOException e) { log.warn("关闭HttpClient失败", e); } } }
额外提醒
哪怕是低流量、无人维护的代码,也建议抽时间修复这个问题——现在花10分钟改代码,能避免未来可能出现的线上故障排查成本。而且Spring Boot环境完全支持try-with-resources,改起来成本很低。
内容的提问来源于stack exchange,提问作者Ori Marko
相关产品推荐
相关产品推荐

