未知JMS选择器时,如何重新连接现有JMS持久订阅?
嘿,我刚从Azure Service Bus转用Apache ActiveMQ的时候,也碰到过一模一样的问题——想直接用已有的持久订阅,却不知道怎么在没选择器的情况下找回并连接上。折腾了一阵,总结出几个实用的方法:
ActiveMQ本身支持JMX管理,这是最直接获取现有订阅详情(包括选择器)的方式。你可以写个简单的工具类,或者用JConsole/VisualVM连接到Broker,直接查看订阅的元数据。
举个Java代码的示例,用来遍历指定Topic的所有持久订阅,拿到选择器:
import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; import org.apache.activemq.broker.jmx.BrokerViewMBean; import org.apache.activemq.broker.jmx.SubscriptionInfo; import org.apache.activemq.broker.jmx.TopicViewMBean; public class ActiveMQSubscriptionLister { public static void main(String[] args) throws Exception { // 连接到ActiveMQ的JMX服务(默认端口1099) JMXConnector connector = JMXConnectorFactory.connect( new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi") ); MBeanServerConnection connection = connector.getMBeanServerConnection(); // 获取Broker的MBean实例 ObjectName brokerObjectName = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost"); BrokerViewMBean broker = (BrokerViewMBean) javax.management.MBeanServerInvocationHandler.newProxyInstance( connection, brokerObjectName, BrokerViewMBean.class, false ); // 遍历指定Topic的订阅(替换成你的Topic名称) String targetTopic = "your-target-topic"; for (TopicViewMBean topic : broker.getTopics()) { if (topic.getName().equals(targetTopic)) { for (SubscriptionInfo sub : topic.getSubscriptions()) { System.out.println("订阅名: " + sub.getSubscriptionName()); System.out.println("ClientID: " + sub.getClientId()); System.out.println("选择器: " + sub.getSelector()); System.out.println("------------------------"); } } } connector.close(); } }
你可以把这个工具集成到你的管理任务里,提前获取到订阅的选择器,然后在消费端用这些参数来创建消费者,确保和原有订阅完全匹配。
如果你的ActiveMQ启用了Web控制台(默认是开启的,端口8161),可以用它的REST/Jolokia接口来查询订阅详情。比如用curl命令:
# 替换admin/admin为你的控制台账号密码,YOUR_TOPIC为目标主题名 curl http://admin:admin@localhost:8161/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Topic,destinationName=YOUR_TOPIC/subscriptions
返回的JSON数据里会包含每个订阅的selector字段,你可以解析这个结果拿到需要的信息。
如果是你自己管理订阅的创建,建议把每个持久订阅的关键参数(订阅名、clientID、选择器)存储到配置文件或数据库里。这样消费端直接读取这些配置,不需要去Broker查询就能准确连接到目标订阅——这也是我现在用的方式,比每次查询更省心。
需要注意的是:ActiveMQ的持久订阅是由clientID + 订阅名 + 选择器共同唯一标识的。如果消费端使用相同的clientID和订阅名,但不指定选择器(或指定不同的选择器),会创建一个新的持久订阅,而不是连接到已有的那个。所以必须确保消费端的参数和原有订阅完全一致。
内容的提问来源于stack exchange,提问作者Maxime Labelle

