使用JMS客户端枚举删除ActiveMQ队列时getQueues返回空集问题
问题根因
你遇到的getQueues()返回空集合不属于代码逻辑错误,是两个容易遗漏的配置和操作问题导致:
- 你在获取
DestinationSource前没有调用connection.start()方法,advisory消息的监听线程不会启动,自然无法接收队列通知 DestinationSource默认仅监听程序运行过程中新产生的队列创建通知,不会主动拉取Broker端已存在的队列列表,这一点官方文档表述存在歧义,你提交的相关issue中社区也确认了属于文档表述遗漏问题。
原有实现修复方案
调整连接参数并添加连接启动逻辑即可让DestinationSource正常拉取已有队列:
// 连接URL开启advisory监听,添加同步现有目的地的参数 String url = "tcp://你的Broker地址:61616?jms.watchTopicAdvisories=true&jms.syncDestinations=true"; ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url); ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); // 必须启动连接才能接收advisory消息 connection.start(); // 预留同步时间,生产环境可添加同步完成的判断逻辑替代固定休眠 Thread.sleep(2000); DestinationSource destinationSource = connection.getDestinationSource(); for (ActiveMQQueue queue : destinationSource.getQueues()) { connection.destroyDestination(queue); } connection.close();
更推荐的队列枚举&清空方案:JMX管理接口
这类Broker端管理操作更推荐使用官方原生的JMX接口实现,不受advisory消息机制限制,稳定性和可控性更高:
前提:Broker端需开启JMX访问,默认本地启动的Broker会自动开启1099端口的JMX服务,远程访问需额外配置JMX远程访问参数。
示例代码如下:
// 连接Broker的JMX服务 JMXServiceURL jmxUrl = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://你的Broker地址:1099/jmxrmi"); JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxUrl, null); MBeanServerConnection mbeanConn = jmxConnector.getMBeanServerConnection(); // 获取Broker管理Bean,brokerName参数需与实际Broker名称一致,默认为localhost ObjectName brokerObjName = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost"); BrokerViewMBean brokerView = MBeanServerInvocationHandler.newProxyInstance(mbeanConn, brokerObjName, BrokerViewMBean.class, true); // 枚举所有队列 for (String queueName : brokerView.getQueues()) { ObjectName queueObjName = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + queueName); QueueViewMBean queueView = MBeanServerInvocationHandler.newProxyInstance(mbeanConn, queueObjName, QueueViewMBean.class, true); // 清空队列消息,若要直接删除队列可调用 brokerView.removeQueue(queueName) queueView.purge(); } jmxConnector.close();
额外注意事项:
- 若仅需要清空队列消息不需要删除队列本身,优先使用
purge()方法,性能远高于删除重建队列 - 队列名称若包含特殊字符,构造
ObjectName时需对特殊字符做转义处理
内容的提问来源于stack exchange,提问作者Wheezil
相关产品推荐
相关产品推荐

