• 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做参考。

  • 相关阅读:
    CentOS 7.1下KVM的安装与配置
    ORACLE常用命令
    linux下输出tomcat控制台信息
    express添加拦截器
    MySQL存储过程
    supervisor提高nodejs调试效率
    Eclipse Jetty调试时无法保存js文件
    eclipse读取含有extjs的项目文件时卡死
    springmvc4+hibernate4+activiti5.18(Maven)
    spring+jersey+c3p0构建restful webservice(数据源采用c3p0)
  • 原文地址:https://www.cnblogs.com/Eternally-dream/p/9896992.html
Copyright © 2020-2023  润新知