• ActiveMQ的Destination高级特性


    1.    Composite Destinations  组合目的地

    组合队列Composite Destinations : 允许用一个虚拟的destination代表多个destinations,这样就可以通过composite destinations在一个操作中同时向多个queue/topic发送消息。
      有两种实现方式:
        第一种:在客户端编码实现
        第二种:在activemq.xml配置文件中实现

    • 第一种:在客户端编码实现

        在composite destinations中,多个destination之间采用","分隔。如下:这里有2个destination  "my-queue3"和"topic://topic-1",这个代表主题模式的topic-1

    private static final String queueName = "my-queue3,topic://topic-1";

      默认是queue模式。

    package cn.qlq.activemq;
    
    import javax.jms.Connection;
    import javax.jms.ConnectionFactory;
    import javax.jms.JMSException;
    import javax.jms.MessageProducer;
    import javax.jms.Queue;
    import javax.jms.Session;
    import javax.jms.TemporaryQueue;
    import javax.jms.TextMessage;
    import org.apache.activemq.ActiveMQConnectionFactory;
    
    /**
     * 生产消息
     */
    public class MsgProducer {
    
        // 默认端口61616
        private static final String url = "tcp://localhost:61616/";
        private static final String queueName = "my-queue3,topic://topic-1";
        private static Session session = null;
    
        public static void main(String[] args) throws JMSException {
            // 1创建ConnectionFactory
            ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
            // 2.由connectionFactory创建connection
            Connection connection = connectionFactory.createConnection();
            // 3.启动connection
            connection.start();
            // 4.创建Session===第一个参数是是否事务管理,第二个参数是应答模式
            session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
            // 5.创建Destination(Queue继承Queue)
            Queue destination = session.createQueue(queueName);
    
            TemporaryQueue temporaryQueue = session.createTemporaryQueue();
    
            // 6.创建生产者producer
            MessageProducer producer = session.createProducer(destination);
            for (int i = 0; i < 5; i++) {
                // 7.创建Message,有好多类型,这里用最简单的TextMessage
                TextMessage tms = session.createTextMessage("textMessage:" + i);
    
                // 设置附加属性
                tms.setStringProperty("str", "stringProperties" + i);
                tms.setJMSPriority(6);
                tms.setJMSReplyTo(temporaryQueue);
    
                // 8.生产者发送消息
                producer.send(tms);
            }
    
            // 9.提交事务
            session.commit();
    
            // 10.关闭connection
            session.close();
            connection.close();
        }
    
    }

      结果会创建5条  my-queue3  队列消息 与 5条 主题模式   topic-1   消息。

      消费者正常消费即可,与队列模型的消息和主题模式的消息消费一样。

    • 第二种:在activemq.xml配置文件中实现
        <broker xmlns="http://activemq.apache.org/schema/core" brokerName="brokerName" dataDirectory="${activemq.data}">
        
            <destinationInterceptors>
               <virtualDestinationInterceptor>
                  <virtualDestinations>
                         <compositeQueue name="comQueue">
                                <forwardTo>
                                       <queue physicalName="queue88" />
                                       <topic physicalName="topic88" />
                                </forwardTo>
                         </compositeQueue>
                  </virtualDestinations>
               </virtualDestinationInterceptor>
            </destinationInterceptors>
        。。。

    程序中向组合队列发送消息:

    package cn.qlq.activemq;
    
    import javax.jms.Connection;
    import javax.jms.ConnectionFactory;
    import javax.jms.JMSException;
    import javax.jms.MessageProducer;
    import javax.jms.Queue;
    import javax.jms.Session;
    import javax.jms.TemporaryQueue;
    import javax.jms.TextMessage;
    import org.apache.activemq.ActiveMQConnectionFactory;
    
    /**
     * 生产消息
     */
    public class MsgProducer {
    
        // 默认端口61616
        private static final String url = "tcp://localhost:61616/";
        private static final String queueName = "comQueue";
        private static Session session = null;
    
        public static void main(String[] args) throws JMSException {
            // 1创建ConnectionFactory
            ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
            // 2.由connectionFactory创建connection
            Connection connection = connectionFactory.createConnection();
            // 3.启动connection
            connection.start();
            // 4.创建Session===第一个参数是是否事务管理,第二个参数是应答模式
            session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
            // 5.创建Destination(Queue继承Queue)
            Queue destination = session.createQueue(queueName);
    
            TemporaryQueue temporaryQueue = session.createTemporaryQueue();
    
            // 6.创建生产者producer
            MessageProducer producer = session.createProducer(destination);
            for (int i = 0; i < 5; i++) {
                // 7.创建Message,有好多类型,这里用最简单的TextMessage
                TextMessage tms = session.createTextMessage("textMessage:" + i);
    
                // 设置附加属性
                tms.setStringProperty("str", "stringProperties" + i);
                tms.setJMSPriority(6);
                tms.setJMSReplyTo(temporaryQueue);
    
                // 8.生产者发送消息
                producer.send(tms);
            }
    
            // 9.提交事务
            session.commit();
    
            // 10.关闭connection
            session.close();
            connection.close();
        }
    
    }

    结果:

      queue88产生五条消息:

       topic88生产五条消息:

     

     2 .Configure Startup Destinations--启动创建队列和主题,只是没有消息

      在启动ActiveMQ的时候如果需要创建Destination的话,可以在activemq.xml中配置:

        <broker xmlns="http://activemq.apache.org/schema/core" brokerName="brokerName" dataDirectory="${activemq.data}">
            <destinations>
                  <queue physicalName="autoqueue" />
                  <topic physicalName="autotopic" />
           </destinations>
        ...

     3.Delete Inactive Destinations---删除没有消息的队列或主题

      在ActiveMQ的queue在不使用之后,可以通过web控制台或者JMX方式来删除掉,当然,也可以通过配置,使得broker可以自动探测到无用的队列并删除掉,回收响应资源。

        <broker xmlns="http://activemq.apache.org/schema/core" brokerName="brokerName" dataDirectory="${activemq.data}" schedulePeriodForDestinationPurge="1000">
            <destinationPolicy>
                  <policyMap>
                    <policyEntries>
                         <policyEntry queue=">" gcInactiveDestinations="true" inactiveTimeoutBeforeGC="30000" />
                    </policyEntries>
                  </policyMap>
           </destinationPolicy>
        。。。

     说明:
      schedulePeriodForDestinationPurge: 设置多长时间检查一次,这里是1秒。
      inactiveTimoutBeforeGC: 设置当Destination为空后,多长时间被删除,这里是30秒。
      gcInactiveDestinations:设置删除掉不活动的队列,默认为false

     4.wildcars(通配符)

      Wildcars用来支持名字分层体系,它不是JMS规范的一部分,是ActiveMQ的扩展。

      ActiveMQ支持以下三种wildcars:
        .     用于作为路径上名字间的分隔符
        *    用于匹配路径上的任何名字
        >   用于递归地匹配任何以这个名字开始的destination

    5.  Destination 选项

    这个是给消费者在JMS规范之外添加的功能特性,通过在队列名称后面使用类似url的语法添加多个选项。包括:
    1 consumer.perfetchSize,消费者持有的未确认的最大消费数量
    2 consumer.maximumPendingMessageLimit: 用来控制非持久化的topic在存在慢消费者的情况下,丢弃的数量,默认为0
    3 consumer.noLocal: 默认false
    4 consumer.dispatchAsync: 是否异步分发,默认true
    5 consumer.retroactive: 是否为回溯消费者,默认false
    6 consumer.selector: JMS的selector,默认null
    7 consumer.exclusive: 是否为独占消费者,默认false
    8 consumer.priority:设置消费者的优先级,默认0

     使用示例:

    Queue queue = new ActiveMQQueue("TEST.QUEUE?consumer.dispatchAsync=
    false&consumer.perfetchSize=10");
    Consumer consumer = session.createConsumer(queue);

    6.    虚拟destination用来创建逻辑destination,客户端可以通过它来生产和消费消息,它会把消息映射到物理destination.

    ActiveMQ支持2种方式:
      1:虚拟主题(Virtual Topics)
      2:组合Destinations(Composite Destinations)

    为什么使用虚拟主题?
      ActiveMQ只有在持久订阅才是持久化的。持久订阅时,每一个持久订阅者,都相当于一个queue的客户端,它会收取所有消息。这种情况下存在两个问题:
    第一:同一应用内消费者端护在均衡的问题。也就是说一个应用程序内的持久化消息,不能使用对个消费者共同承担消息处理能力。因为每个消费者都会获取所有消息。因为每一个消费者都会获取所有信息。
    Queue到时可以解决这个问题,但broker端又不能将消息发送到多个应用端,所以纪要发布订阅,又要让消费者分组,这个功能JMS本身是没有的
    第二:同一应用内消费者端failover问题,由于只能使用单个的持久订阅者,如果这个订阅者出错,则应用就无法处理,系统的健壮性不高。

    如何使用虚拟topic?
    第一:对于消息发布者来说,就是一个正常的topic,名称以VirtualTopic.开始,比如VirtualTopic.Orders,代码示例如下:

    Topicdestination = session.createTopic("VirtualTopic.Orders");

    第二:对于消息接收端来说,是个队列,不同应用里使用不同的前缀作为队列名称,即可表明自己的身份即可实现消费端应用分组。
    例如Consumer.A.VirtualTopic.Orders说明它是名称为A的消费端,同理Consumer.B VirtualTopic.Orders说明是一名称为B的消费端。可以在同一个应用中使用多个消费者消费这个队列
    又因为不同应用使用的topic名称不一样,前缀不同,所以不同应用中都可以接受到全部消息。每一个客户端相当于一个持久订阅者,而且这个客户端可以使用多个消费者共同来承担消费任务。

    代码示例:

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

    生产者代码:

    package cn.qlq.activemq.topic;
    
    import javax.jms.Connection;
    import javax.jms.ConnectionFactory;
    import javax.jms.Destination;
    import javax.jms.JMSException;
    import javax.jms.MessageProducer;
    import javax.jms.Session;
    import javax.jms.TextMessage;
    
    import org.apache.activemq.ActiveMQConnectionFactory;
    
    public class MsgProducer {
    
        private static final String url = "tcp://127.0.0.1:61616";
        private static final String topicName = "VirtualTopic.Orders";
    
        public static void main(String[] args) throws JMSException {
            ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
    
            Connection connection = connectionFactory.createConnection();
    
            connection.start();
    
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    
            Destination destination = session.createTopic(topicName);
    
            MessageProducer producer = session.createProducer(destination);
            for (int i = 0; i < 10; i++) {
    
                TextMessage tms = session.createTextMessage("textMessage:" + i);
    
                producer.send(tms);
    
                System.out.println("send:" + tms.getText());
            }
            connection.close();
        }
    
    }

    消费者代码:

    package cn.qlq.activemq;
    
    import java.util.Enumeration;
    
    import javax.jms.Connection;
    import javax.jms.ConnectionFactory;
    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.MessageConsumer;
    import javax.jms.MessageListener;
    import javax.jms.Queue;
    import javax.jms.Session;
    import javax.jms.TextMessage;
    
    import org.apache.activemq.ActiveMQConnectionFactory;
    
    /**
     * 消费消息
     * 
     * @author QiaoLiQiang
     * @time 2018年9月18日下午11:26:41
     */
    public class MsgConsumer {
    
        // 默认端口61616
        private static final String url = "tcp://localhost:61616/";
        private static final String queueName = "Consumer.A.VirtualTopic.Orders";
    
        public static void main(String[] args) throws JMSException {
            // 1创建ConnectionFactory
            ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
            // 2.由connectionFactory创建connection
            Connection connection = connectionFactory.createConnection();
            Enumeration jmsxPropertyNames = connection.getMetaData().getJMSXPropertyNames();
            while (jmsxPropertyNames.hasMoreElements()) {
                String nextElement = (String) jmsxPropertyNames.nextElement();
                System.out.println("JMSX name ===" + nextElement);
            }
            // 3.启动connection
            connection.start();
            // 4.创建Session===第一个参数是是否事务管理,第二个参数是应答模式
            Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
            // 5.创建Destination(Queue继承Queue)
            Queue destination = session.createQueue(queueName);
            // 6.创建消费者consumer
            MessageConsumer consumer = session.createConsumer(destination);
    
            int i = 0;
            while (i < 5) {
                TextMessage textMessage = (TextMessage) consumer.receive();
                System.out.println("接收消息:" + textMessage.getText() + ";属性" + textMessage.getStringProperty("str"));
                i++;
    
                if (i == 5) {// 确保消费完所有的消息再进行确认
                    textMessage.acknowledge();
                }
            }
    
            // 提交事务,进行确认收到消息
            session.commit();
    
            session.close();
            connection.close();
        }
    }

    其实把消费者队列化了。

    修改虚拟主题的前缀:

    默认前缀是VirtualTopic.>

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

    修改配置:

    <broker xmlns="http://activemq.apache.org/schema/core">
           <destinationInterceptors>
                  <virtualDestinationInterceptor>
                         <virtualDestinations>
                                <virtualTopic name=">" prefix="VirtualTopicConsumers.*." selectorAware="false" />
                         </virtualDestinations>
                  </virtualDestinationInterceptor>
           </destinationInterceptors>
    </broker>
  • 相关阅读:
    Linux之权限
    Linux基础和文件操作
    linux之用户、用户组、用户提权
    linux之Vim使用
    java面向对象
    eclipse首选项常用设置
    eclipse中添加项目运行程序
    eclipse的基本配置
    eclipse安装
    Jemter压力测试核心流程
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/10580407.html
Copyright © 2020-2023  润新知