MQTTClient构造方法中getConnection获取的资源未全场景释放,如何正确关闭?
public MQTTClient(MQTTConnectionInfo conn, ConnectionMgr conmgr) throws Exception { try { clientId = conn.getClientId(); mqttClient = ClientFactory.getConnection(conn, conmgr); username =conn.getUsername(); log.info("-- inside MqttClient == While Connecting : "+username.toString() + mqttClient.getState()); } catch (Exception e) { e.printStackTrace(); throw e; } }
漏洞原因分析
- 当
ClientFactory.getConnection执行成功、已经拿到MQTT连接实例后,后续的conn.getUsername()、username.toString()、日志打印等任意一步抛出异常时,代码会直接进入catch块向外抛出异常,已经创建成功的MQTT连接没有被回收,就会出现资源泄漏。
修复方案
方案1:构造方法内异常场景主动回收资源
调整try-catch逻辑,在后续操作抛出异常时,先关闭已经创建的连接再向外抛出异常即可:
public MQTTClient(MQTTConnectionInfo conn, ConnectionMgr conmgr) throws Exception { Exception businessEx = null; mqttClient = null; try { clientId = conn.getClientId(); mqttClient = ClientFactory.getConnection(conn, conmgr); username = conn.getUsername(); log.info("-- inside MqttClient == While Connecting : "+username.toString() + mqttClient.getState()); } catch (Exception e) { businessEx = e; e.printStackTrace(); throw e; } finally { // 仅发生业务异常、且连接已创建成功的场景下关闭连接 if (businessEx != null && mqttClient != null) { try { // 可根据实际使用的MQTT客户端API替换为对应的关闭/断开连接方法 mqttClient.close(); } catch (Exception closeEx) { // 关闭异常仅打印日志即可,不要覆盖原始业务异常 log.error("MQTT连接关闭失败", closeEx); } } } }
方案2:类实现AutoCloseable接口,支持外部自动回收
如果MQTTClient实例的生命周期由调用方控制,可以让类实现AutoCloseable接口,在close方法中统一释放连接,调用方可以通过try-with-resources语法自动关闭资源,覆盖所有场景下的资源回收需求:
// MQTTClient类实现AutoCloseable接口 public class MQTTClient implements AutoCloseable { // 原有类属性、方法保留 @Override public void close() throws Exception { if (mqttClient != null) { mqttClient.close(); } } public MQTTClient(MQTTConnectionInfo conn, ConnectionMgr conmgr) throws Exception { clientId = conn.getClientId(); mqttClient = ClientFactory.getConnection(conn, conmgr); username = conn.getUsername(); log.info("-- inside MqttClient == While Connecting : "+username.toString() + mqttClient.getState()); } } // 调用方使用示例 try (MQTTClient client = new MQTTClient(conn, conmgr)) { // 执行业务逻辑 } catch (Exception e) { e.printStackTrace(); } // 执行完成出try块后会自动调用close方法释放连接,无论是否发生异常都不会泄漏资源
内容的提问来源于stack exchange,提问作者Anupama Bali
相关产品推荐
相关产品推荐

