ActiveMQ学习笔记(14)----Destination高级特性(二) ActiveMQ学习笔记(14)----Destination高级特性(二)

1. Visual Destinations

  1.1 概述

  虚拟Destination用来创建逻辑Destinations,客户端可以通过它来产生和消费消息,它会把消息映射到物理Destinations。ActiveMQ支持两种方式:

  1. 虚拟主题(Virtual Topics)

  2. 组合Destinations (Composite Destinations)

  1.2 为何使用虚拟主题

  ActiveMQ中,topic只有在持久订阅下才会持久化,持久订阅时,每个订阅者,都相当于一个queue的客户端,它会收取所有消息,这种情况下存在两个问题:

  1. 同一个应用内的consumer端负载均衡的问题,也就是同一个应用上的一个持久订阅者不能使用多个consumer来共同承担消息处理功能,因为每个consumer都会获取所有消息。

  2. 同一应用内的consumer端的failover问题:由于只能使用单个的持久订阅者,如果这个订阅者出错,则应用就无法处理消息了,系统的健壮性不高。

  为了解决这两个问题,ActiveMQ中实现了虚拟的Topic的功能。

  1.3 如何使用虚拟主题

  1. 对于消息发布者来说,就是一个正常的Topic,名称以VirtualTopic开头。例如

  VirtualTopic.Orders.代码示例如下:

Topic destination = session.createTopic("VirtualTopic.Orders");

  2. 对于消息接收端来说,是一个队列,不同应用里面应使用不同的前缀作为队列的名称,即可表明自己的身份,即可实现消费端应用的分组。

  例如Consumer.A.VritualTopic.Orders,说明它是名称A的消费端,同理Consumer.B.VritualTopic.Orders表示时一个名称为B的客户端,可以在同一个应用里面使用多个consumer消费此queue,则可以实现上面两个功能。

  又因为不同应用使用的queue名称不同(前缀不同),所以不同的应用中都可以接收到全部的消息,每个客户端相当于一个持久订阅者,而且这个客户端可以使用多个消费者来共同承担消费任务,代码示例如下:

 Destination destiantion = session.createQueue("Consumer.A.VirtualTopic.Orders“);

  完整得测试代码如下:

  消息发送者

 
package com.wangx.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*; public class TopicSender { public static void main(String[] args) throws JMSException { ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); Connection connection = factory.createConnection(); Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE); //创建虚拟主题,加前缀VirtualTopic Topic topic = session.createTopic("VirtualTopic.myTopic"); MessageProducer producer = session.createProducer(topic); producer.setDeliveryMode(DeliveryMode.PERSISTENT); connection.start(); for (int i = 0; i < 30; i++) { TextMessage textMessage = session.createTextMessage("topic消息===" + i); producer.send(textMessage); } session.commit(); connection.close(); } }
 

  A客户端代码(只有一个消费者)

 
package com.wangx.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*; public class QR1 { public static void main(String[] args) throws JMSException { ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); Connection connection = factory.createConnection(); connection.start(); final Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE); //创建队列 Destination destination = session.createQueue("Consumer.A.VirtualTopic.myTopic"); MessageConsumer consumer = session.createConsumer(destination); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { TextMessage textMessage = (TextMessage) message; try { System.out.println("Consumer.A.接收到得消息:" + textMessage.getText()); session.commit(); } catch (JMSException e) { e.printStackTrace(); } } }); } }
 

  B客户端代码,有两个消费者

 
package com.wangx.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*; public class QR2 { public static void main(String[] args) throws JMSException { ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); Connection connection = factory.createConnection(); connection.start(); final Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE); //创建队列 Destination destination = session.createQueue("Consumer.B.VirtualTopic.myTopic"); final MessageConsumer consumer = session.createConsumer(destination); final MessageConsumer messageConsumer = session.createConsumer(destination); //模拟多个consumer消费一个queue new Thread(new Runnable() { @Override public void run() { try { consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { TextMessage textMessage = (TextMessage) message; try { System.out.println("Consumer.B-->consumer接收到消息:" + textMessage.getText()); session.commit(); } catch (JMSException e) { e.printStackTrace(); } } }); } catch (JMSException e) { e.printStackTrace(); } } }).start(); new Thread(new Runnable() { @Override public void run() { try { messageConsumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { TextMessage textMessage = (TextMessage) message; try { System.out.println("Consumer.B-->messageConsumer接收到消息:" + textMessage.getText()); session.commit(); } catch (JMSException e) { e.printStackTrace(); } } }); } catch (JMSException e) { e.printStackTrace(); } } }).start(); } }
 

  在接收消息之前,应该先运行一下consumer客户端,将消费者注册到Broker中。

  3. 默认虚拟主题得前缀是:VirtualTopic.>

  自定义消费虚拟地址默认格式:Consumer.*.VirtualTopic.>

  自定义消费虚拟地址可以改,比如下面的配置就把它修改了。

  xml配置如下

 
<broker xmlns="http:/activemq.apache.org/schema/core">

    <destinationInterceptors>       <virtualDestinationInterceptor>         <virtualDestinations>           <virtualTopic name=">" prefix="VirtualTopicConsumers.*." selectorAware="false"/>         </virtualDestinations>       </virtualDestinationInterceptor>     </destinationInterceptors>   </broker>
 

  配置之后将consumer端的相应前缀修改即可。

2. Mirrored Queues

  2.1 概述

   ActiveMQ中每个queue中的消息只能被一个consumer消费,然而,有时候你可能希望能够监视生产者和消费者之间的消息流。你可以通过Virtual Destinations来建立一个virtual queue 来把消息发送到多个queues中。但是,为系统中没给queue都进行如此配置可能会很麻烦。

  2.1使用

  ActiveMQ支持Mirrored Queues。Broker会把发送到某个queue的所有消息都转发到一个名称类似的topic,因此监控程序只需要订阅这个mirrored queue topic。为了启用Mirrored Queues,首先将Broker Service的useMirroredQueues属性设置成true,然后可以通过destinationInterceptors设置其他属性,如:mirror topic的前缀,缺省是:“VirtualTopic.Mirror.".

    比如修改后的配置如下

<destinationInterceptors>
            <mirroredQueue copyMessage="true" postfix=".qmirror" prefix=""/> </destinationInterceptors>

  在我的配置中并没有配置配置前缀,但是一定需要配置copyMessage="true",查看控制台如下

  存在默认前缀的topic,此时只需要用一个消费者去消费该topic中的消息就可以了。

3. Per Destination Policies

  ActiveMQ支持多种不同的策略,来单独配置每一个Destination,它的属性很多,可以参考官方文档:

  http://activemq.apache.org/per-destination-policies.html

  官方文档最后还给出了一个demo做参考。

原文 ActiveMQ学习笔记(14)----Destination高级特性(二)

1. Visual Destinations

  1.1 概述

  虚拟Destination用来创建逻辑Destinations,客户端可以通过它来产生和消费消息,它会把消息映射到物理Destinations。ActiveMQ支持两种方式:

  1. 虚拟主题(Virtual Topics)

  2. 组合Destinations (Composite Destinations)

  1.2 为何使用虚拟主题

  ActiveMQ中,topic只有在持久订阅下才会持久化,持久订阅时,每个订阅者,都相当于一个queue的客户端,它会收取所有消息,这种情况下存在两个问题:

  1. 同一个应用内的consumer端负载均衡的问题,也就是同一个应用上的一个持久订阅者不能使用多个consumer来共同承担消息处理功能,因为每个consumer都会获取所有消息。

  2. 同一应用内的consumer端的failover问题:由于只能使用单个的持久订阅者,如果这个订阅者出错,则应用就无法处理消息了,系统的健壮性不高。

  为了解决这两个问题,ActiveMQ中实现了虚拟的Topic的功能。

  1.3 如何使用虚拟主题

  1. 对于消息发布者来说,就是一个正常的Topic,名称以VirtualTopic开头。例如

  VirtualTopic.Orders.代码示例如下:

Topic destination = session.createTopic("VirtualTopic.Orders");

  2. 对于消息接收端来说,是一个队列,不同应用里面应使用不同的前缀作为队列的名称,即可表明自己的身份,即可实现消费端应用的分组。

  例如Consumer.A.VritualTopic.Orders,说明它是名称A的消费端,同理Consumer.B.VritualTopic.Orders表示时一个名称为B的客户端,可以在同一个应用里面使用多个consumer消费此queue,则可以实现上面两个功能。

  又因为不同应用使用的queue名称不同(前缀不同),所以不同的应用中都可以接收到全部的消息,每个客户端相当于一个持久订阅者,而且这个客户端可以使用多个消费者来共同承担消费任务,代码示例如下:

 Destination destiantion = session.createQueue("Consumer.A.VirtualTopic.Orders“);

  完整得测试代码如下:

  消息发送者

 
package com.wangx.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*; public class TopicSender { public static void main(String[] args) throws JMSException { ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); Connection connection = factory.createConnection(); Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE); //创建虚拟主题,加前缀VirtualTopic Topic topic = session.createTopic("VirtualTopic.myTopic"); MessageProducer producer = session.createProducer(topic); producer.setDeliveryMode(DeliveryMode.PERSISTENT); connection.start(); for (int i = 0; i < 30; i++) { TextMessage textMessage = session.createTextMessage("topic消息===" + i); producer.send(textMessage); } session.commit(); connection.close(); } }
 

  A客户端代码(只有一个消费者)

 
package com.wangx.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*; public class QR1 { public static void main(String[] args) throws JMSException { ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); Connection connection = factory.createConnection(); connection.start(); final Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE); //创建队列 Destination destination = session.createQueue("Consumer.A.VirtualTopic.myTopic"); MessageConsumer consumer = session.createConsumer(destination); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { TextMessage textMessage = (TextMessage) message; try { System.out.println("Consumer.A.接收到得消息:" + textMessage.getText()); session.commit(); } catch (JMSException e) { e.printStackTrace(); } } }); } }
 

  B客户端代码,有两个消费者

 
package com.wangx.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*; public class QR2 { public static void main(String[] args) throws JMSException { ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); Connection connection = factory.createConnection(); connection.start(); final Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE); //创建队列 Destination destination = session.createQueue("Consumer.B.VirtualTopic.myTopic"); final MessageConsumer consumer = session.createConsumer(destination); final MessageConsumer messageConsumer = session.createConsumer(destination); //模拟多个consumer消费一个queue new Thread(new Runnable() { @Override public void run() { try { consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { TextMessage textMessage = (TextMessage) message; try { System.out.println("Consumer.B-->consumer接收到消息:" + textMessage.getText()); session.commit(); } catch (JMSException e) { e.printStackTrace(); } } }); } catch (JMSException e) { e.printStackTrace(); } } }).start(); new Thread(new Runnable() { @Override public void run() { try { messageConsumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { TextMessage textMessage = (TextMessage) message; try { System.out.println("Consumer.B-->messageConsumer接收到消息:" + textMessage.getText()); session.commit(); } catch (JMSException e) { e.printStackTrace(); } } }); } catch (JMSException e) { e.printStackTrace(); } } }).start(); } }
 

  在接收消息之前,应该先运行一下consumer客户端,将消费者注册到Broker中。

  3. 默认虚拟主题得前缀是:VirtualTopic.>

  自定义消费虚拟地址默认格式:Consumer.*.VirtualTopic.>

  自定义消费虚拟地址可以改,比如下面的配置就把它修改了。

  xml配置如下

 
<broker xmlns="http:/activemq.apache.org/schema/core">

    <destinationInterceptors>       <virtualDestinationInterceptor>         <virtualDestinations>           <virtualTopic name=">" prefix="VirtualTopicConsumers.*." selectorAware="false"/>         </virtualDestinations>       </virtualDestinationInterceptor>     </destinationInterceptors>   </broker>
 

  配置之后将consumer端的相应前缀修改即可。

2. Mirrored Queues

  2.1 概述

   ActiveMQ中每个queue中的消息只能被一个consumer消费,然而,有时候你可能希望能够监视生产者和消费者之间的消息流。你可以通过Virtual Destinations来建立一个virtual queue 来把消息发送到多个queues中。但是,为系统中没给queue都进行如此配置可能会很麻烦。

  2.1使用

  ActiveMQ支持Mirrored Queues。Broker会把发送到某个queue的所有消息都转发到一个名称类似的topic,因此监控程序只需要订阅这个mirrored queue topic。为了启用Mirrored Queues,首先将Broker Service的useMirroredQueues属性设置成true,然后可以通过destinationInterceptors设置其他属性,如:mirror topic的前缀,缺省是:“VirtualTopic.Mirror.".

    比如修改后的配置如下

<destinationInterceptors>
            <mirroredQueue copyMessage="true" postfix=".qmirror" prefix=""/> </destinationInterceptors>

  在我的配置中并没有配置配置前缀,但是一定需要配置copyMessage="true",查看控制台如下

  存在默认前缀的topic,此时只需要用一个消费者去消费该topic中的消息就可以了。

3. Per Destination Policies

  ActiveMQ支持多种不同的策略,来单独配置每一个Destination,它的属性很多,可以参考官方文档:

  http://activemq.apache.org/per-destination-policies.html

  官方文档最后还给出了一个demo做参考。

猜你喜欢

转载自www.cnblogs.com/xiaoshen666/p/10854708.html