• ActiveMQ安装与入门程序 & JMS的消息结构


    1.Activemq安装

      直接到官网下载:记住apache的官网是域名反过来,比如我们找activemq就是activemq.apache.org

      最新版本要求最低的JDK是8,所以最好在电脑装多个版本的JDK,用的时候切换就 可以了。

      下载完成是个压缩包,解压目录如下:

          

    1.启动:%activemq%apache-activemq-5.15.6inwin64activemq.bat启动即可,日志如下:(可以看出是集成就wrapper)

        

      

      访问:http://localhost:8161/进行测试:

      点击上面圈住的地方进入管理界面:(activemq的默认账号和密码都是admin)

    补充:

      1.activemq内置jetty服务器,后台管理端口在confjetty.xml中进行配置;,默认是8161:

      2.接收消息的端口在confactivemq.xml),默认是61616--而且只有openwire有用,其他可以注释掉

    2.我们肯定不可能一直开在窗口,所以需要注册为服务:

       以管理员方式运行:   %activemq%apache-activemq-5.15.6inwin64InstallService.bat

       查看源码发现是以wrapper的方式注册为服务。

    2.入门程序

      我将上一篇的JMS编程图放在这里便于理解:

    依赖的jar包:activemq-all-5.15.6.jar下载的zip包里面带的有 

    开发过程基本如下:

      JMS的消息队列有两种模式,一般队列模型又称为P2P模式,PUBSUB又称为主题模式

     1.队列模型---生产消息的程序: 

    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.TextMessage;
    
    import org.apache.activemq.ActiveMQConnectionFactory;
    
    /**
     * 生产消息
     * 
     * @author QiaoLiQiang
     * @time 2018年9月18日下午11:04:41
     */
    public class MsgProducer {
    
        // 默认端口61616
        private static final String url = "tcp://localhost:61616/";
        private static final String queueName = "myQueue";
    
        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 session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            // 5.创建Destination(Queue继承Queue)
            Queue destination = session.createQueue(queueName);
            // 6.创建生产者producer
            MessageProducer producer = session.createProducer(destination);
            for (int i = 0; i < 100; i++) {
                // 7.创建Message,有好多类型,这里用最简单的TextMessage
                TextMessage tms = session.createTextMessage("textMessage:" + i);
                // 8.生产者发送消息
                producer.send(tms);
    
                System.out.println("send:" + tms.getText());
            }
            // 9.关闭connection
            connection.close();
        }
    
    }

    结果:

      .....  

    send:textMessage:93
    send:textMessage:94
    send:textMessage:95
    send:textMessage:96
    send:textMessage:97
    send:textMessage:98
    send:textMessage:99

    到activemq的管理界面查看:

     2.队列模型---消费者代码:

    package cn.qlq.activemq;
    
    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 = "myQueue";
    
        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 session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            // 5.创建Destination(Queue继承Queue)
            Queue destination = session.createQueue(queueName);
            // 6.创建消费者consumer
            MessageConsumer consumer = session.createConsumer(destination);
            // 7.给消费者绑定监听器(消息的监听是一个异步的过程,不可以关闭连接,绑定监听器线程是一直开启的,处于阻塞状态,所以可以在程序退出关闭)
            consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    // 7.1由于消费者接受的是TextMessage,所以强转一下
                    TextMessage tms = (TextMessage) message;
                    try {
                        System.out.println("接收消息:" + tms.getText());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    
    }

      当然接收消息也可以使用consumer.receive();进行接收,如下:

            // 7.receive是一个阻塞方法
            Message message = consumer.receive();
            while (message != null) {
                TextMessage txtMsg = (TextMessage) message;
                session.commit();
                System.out.println("收到消 息:" + txtMsg.getText());
                message = consumer.receive(1000L);
            }

     启动结果:(接受完线程并不关闭,所以是异步接收,线程处于阻塞状态。)

    再开一个消费者:再运行一次消费者程序。

    后台管理查看:(两个消费者)

    在启动生产者生产一百条消息之后查看消费者:(切记切换控制台按钮查看消费信息):两个消费者平均消费信息,满足上一篇介绍的队列模型

    第一个消费者:

     第二个消费者:

     

    补充:关于事务的介绍。

      如果connection.createSession(true, Session.AUTO_ACKNOWLEDGE);的第一个参数为true,也就是开启事务,在事务性会话中,事务需要被提交,也就是提交之后才能最最终的数据产生影响。否则不会发送消息或者消费消息。也就是虽然send(msg),即使你不commit也不会生成消息。

      如果传的参数为false,也就是不开启事务,消息何时被确认取决于创建会话的应答模式。一般如果是非事务环境,应答模式是  Session.AUTO_ACKNOWLEDGE ,会自动确认,也就是生产者调用send或者接受者调用recrive的时候就会自动对最终的结果产生影响。

    如下是带有事务的操作代码:

    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.TextMessage;
    
    import org.apache.activemq.ActiveMQConnectionFactory;
    
    /**
     * 生产消息
     * 
     * @author QiaoLiQiang
     * @time 2018年9月18日下午11:04:41
     */
    public class MsgProducer {
    
        // 默认端口61616
        private static final String url = "tcp://localhost:61616/";
        private static final String queueName = "myQueue";
        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(true, Session.AUTO_ACKNOWLEDGE);
            // 5.创建Destination(Queue继承Queue)
            Queue destination = session.createQueue(queueName);
            // 6.创建生产者producer
            MessageProducer producer = session.createProducer(destination);
            for (int i = 0; i < 10; i++) {
                // 7.创建Message,有好多类型,这里用最简单的TextMessage
                TextMessage tms = session.createTextMessage("textMessage:" + i);
    
                // 设置附加属性
                tms.setStringProperty("str", "stringProperties" + i);
    
                // 8.生产者发送消息
                producer.send(tms);
            }
    
            // 9.提交事务
            session.commit();
    
            // 10.关闭connection
            session.close();
            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 = "myQueue";
    
        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.AUTO_ACKNOWLEDGE);
            // 5.创建Destination(Queue继承Queue)
            Queue destination = session.createQueue(queueName);
            // 6.创建消费者consumer
            MessageConsumer consumer = session.createConsumer(destination);
    
            int i = 0;
            while (i < 10) {
                TextMessage textMessage = (TextMessage) consumer.receive();
                System.out.println("接收消息:" + textMessage.getText() + ";属性" + textMessage.getStringProperty("str"));
                i++;
    
                // 提交事务,进行确认收到消息
                session.commit();
            }
    
            session.close();
            connection.close();
        }
    
    }

    3.主题模型---生产消息的程序:

      与队列模式一样,只是Destination是Topic。

    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;
    
    /**
     * 主题模式的消息生产者
     * 
     * @author QiaoLiQiang
     * @time 2018年9月19日下午10:10:36
     */
    public class MsgProducer {
    
        // 默认端口61616
        private static final String url = "tcp://localhost:61616/";
        private static final String topicName = "myTopic";
    
        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 session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            // 5.创建Destination(Queue继承Queue,Topic也继承Destination==这三个都是接口)
            Destination destination = session.createTopic(topicName);
            // 6.创建生产者producer
            MessageProducer producer = session.createProducer(destination);
            for (int i = 0; i < 100; i++) {
                // 7.创建Message,有好多类型,这里用最简单的TextMessage
                TextMessage tms = session.createTextMessage("textMessage:" + i);
                // 8.生产者发送消息
                producer.send(tms);
    
                System.out.println("send:" + tms.getText());
            }
            // 9.关闭connection
            connection.close();
        }
    
    }

    4.主题模式---消息消费者:

    与队列模式一样,只是Destination是Topic。

    package cn.qlq.activemq.topic;
    
    import javax.jms.Connection;
    import javax.jms.ConnectionFactory;
    import javax.jms.Destination;
    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.MessageConsumer;
    import javax.jms.MessageListener;
    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 topicName = "myTopic";
    
        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 session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            // 5.创建Destination(Queue继承Queue,Topic也继承Destination==这三个都是接口)
            Destination destination = session.createTopic(topicName);
            // 6.创建消费者consumer
            MessageConsumer consumer = session.createConsumer(destination);
            // 7.给消费者绑定监听器(消息的监听是一个异步的过程,不可以关闭连接,绑定监听器线程是一直开启的,处于阻塞状态,所以可以在程序退出关闭)
            consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    // 7.1由于消费者接受的是TextMessage,所以强转一下
                    TextMessage tms = (TextMessage) message;
                    try {
                        System.out.println("接收消息:" + tms.getText());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    
    }

     补充:上面的步骤7接收消息可以用receive()进行接收,该方法也是阻塞方法。

            // 7.receive是一个阻塞方法
            Message message = consumer.receive();
            while (message != null) {
                TextMessage txtMsg = (TextMessage) message;
                session.commit();
                System.out.println("收到消 息:" + txtMsg.getText());
                message = consumer.receive(1000L);
            }

    测试:

      先启动生产者生成100条消息:

          

       启动两个消费者,不会消费消息,满足消费者不能消费订阅之前就发送到主题中的消息:

      再启动生产者发布100条消息,查看后台管理界面和消费者控制台信息:

            

          

        两个消费者控制台一样:(满足主题中的消息被所有订阅者消费)

          

    3.JMS的消息结构

    JMS由下面三部分组成:消息头、属性、消息体

    1.消息头 :  包含消息的识别信息和路由信息,

    消息头包含一些标准的属性如下:

    下面是进一步的解释:

    1.JMSDestination:消息发送的目的地,主要是指Queue和Topic,自动分配,由下面程序识别:

    // 5.创建Destination(Queue继承Queue)
            Queue destination = session.createQueue(queueName);

    2.JMSDeliveryMode:传送模式。两种:持久模式和非持久模式。一条持久性消息应该被传送"一次仅仅一次",这就意味着如果JMS系统出现故障,该消息并不会丢失,它会在服务器恢复之后再次传递。一条非持久的消息最多会传送一次,这意味着服务器出现故障,该消息将丢失。自动分配

     3.JMSExpiration:消息过期时间,等于send方法中的timeToLive的值加上发送时刻的GMT时间值。如果值为0表示永不过期。如果发送后,在消息过期时间之后还没有被发送到目的地,则该消息会被清除。自动分配

     4.JMSPriority:优先级,0-9十个级别。默认是4。0-4是普通消息,5-9是加急消息。自动分配

    5.JMSMessageID:每个消息的唯一标识。由JMS Provider产生。自动生成

     6.JMSTimestamp:JMS Provider在调用send()方法时自动设置的。它是消息被发送和消费者实际接收的时间差。自动分配

    7.JMSCorrelationID:用来连接到另一个消息,典型的应用是在回复消息中连接到原消息。JMSCorrelationID一般用于将一条消息标记为对JMSMessageID标识的上一条消息的应答,不过它的值可以是任何值。由开发者设置

    8.JMSReplyTo:本消息回复消息的目的地,开发者设置

    9.JMSType:消息类型的识别符。开发者设置

    10.JMSRedelivered:(重新投递)如果一个客户端收到了一个消息的此参数设置为true,则表示可能客户端在早些时候收到过消息,但是并没有签收(Ack)。如果该消息被重新传送,JMSRedelivered=true。反之,JMSRedelivered=false。自动生成

    2.消息体:  

      JMS定义的五种类型的消息体格式,也叫消息类型,包括:TextMessage、MapMessage、ObjectMessage、BytesMessage、和StreamMessage等五种

    参考:https://www.cnblogs.com/qlqwjy/p/10463660.html

        

    3.消息属性

    包含下面三种类型的消息属性:

    • 应用程序设置和添加的属性,如下:

                // 设置附加属性
                tms.setStringProperty("str", "stringProperties" + i);
    • JMS定义的属性

    使用"JMSX"作为属性名的前缀。如下方法可以返回所有连接支持的JMSX属性的名字。

    connection.getMetaData().getJMSXPropertyNames();
    • JMS供应商特定的属性

    如下:生产者代码:

    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.TextMessage;
    
    import org.apache.activemq.ActiveMQConnectionFactory;
    
    /**
     * 生产消息
     * 
     * @author QiaoLiQiang
     * @time 2018年9月18日下午11:04:41
     */
    public class MsgProducer {
    
        // 默认端口61616
        private static final String url = "tcp://localhost:61616/";
        private static final String queueName = "myQueue";
        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(false, Session.AUTO_ACKNOWLEDGE);
            // 5.创建Destination(Queue继承Queue)
            Queue destination = session.createQueue(queueName);
            // 6.创建生产者producer
            MessageProducer producer = session.createProducer(destination);
            for (int i = 0; i < 1; i++) {
                // 7.创建Message,有好多类型,这里用最简单的TextMessage
                TextMessage tms = session.createTextMessage("textMessage:" + i);
                tms.setJMSDeliveryMode(1);
                tms.setJMSExpiration(10 * 1000);
                tms.setJMSPriority(5);
                tms.setJMSMessageID(i + "MessageId");
                tms.setJMSTimestamp(5 * 1000);
                tms.setJMSCorrelationID("JMSCorrelationID" + i);
                tms.setJMSReplyTo(destination);
                tms.setJMSType("JMSType" + i);
    
                // 设置附加属性
                tms.setStringProperty("str", "stringProperties" + i);
    
                // 8.生产者发送消息
                producer.send(tms);
            }
            // 9.关闭connection
            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 = "myQueue";
    
        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(false, Session.AUTO_ACKNOWLEDGE);
            // 5.创建Destination(Queue继承Queue)
            Queue destination = session.createQueue(queueName);
            // 6.创建消费者consumer
            MessageConsumer consumer = session.createConsumer(destination);
    
            int i = 0;
            while (i < 1) {
                i++;
                TextMessage textMessage = (TextMessage) consumer.receive();
                System.out.println("接收消息:" + textMessage.getText() + ";属性" + textMessage.getStringProperty("str"));
            }
        }
    
    }

     结果:

    JMSX name ===JMSXUserID
    JMSX name ===JMSXGroupID
    JMSX name ===JMSXGroupSeq
    JMSX name ===JMSXDeliveryCount
    JMSX name ===JMSXProducerTXID
    接收消息:textMessage:0;属性stringProperties0

  • 相关阅读:
    【贪心】CodeForces-545C:Woodcutters
    【贪心】雷达问题
    【贪心】poj1328:雷达设置
    【最短路】HDU2680:Choose the best route
    2018年第四阶段组队训练赛第九场
    第四阶段组队训练赛第八场
    2018年第四阶段组队训练赛第七场
    第四阶段组队训练赛第六场( 题源:UKIEPC2017)
    Coins I
    2018年第四阶段组队训练赛第五场
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/9671981.html
Copyright © 2020-2023  润新知