JMS Activemq实战例子demo

来源:互联网 发布:mac下的虚拟机 编辑:程序博客网 时间:2024/06/09 22:39

上一篇已经讲了JMS的基本概念,这一篇来上手练一练,如果对JMS基本概念还不熟悉,欢迎参靠JMS基本概。


这篇文章所使用的代码已经不是我刚入手时的代码,已经经过我重构过的代码,便于理解,并且加了很多中文注释,希望对大家有所帮助。


在基本概念一篇中已经讲到,JMS有两种消息模型,一种是点对点,另一种的发布/订阅模式。本篇文章就基于这两种消息模型来写例子。


点对点模型


        先看一下生产者代码:

package com.darren.activemq.queue;import javax.jms.JMSException;import javax.jms.Session;import javax.jms.TextMessage;import com.darren.activemq.ActivemqContants;import com.darren.activemq.ProducerConsumer;/** * 消息生产类 *  * @author Darren * */public class QueueProducer extends ProducerConsumer {    private int startNumber;    private int endNumber;    public QueueProducer(String name) throws JMSException {        this.name = name;        // 通过连接工厂获取连接        this.connection = this.getConnection();        // 启动连接        this.connection.start();        // 创建Session        this.session = this.connection.createSession(true, Session.AUTO_ACKNOWLEDGE);        // 创建消息队列        this.destination = this.session.createQueue("test-queue");        // 创建消息生产者        this.messageProducer = this.session.createProducer(destination);    }    /**     * 发送消息     *      * @throws JMSException     */    public void sendMessage() throws JMSException {        this.startNumber = this.endNumber;        this.endNumber = this.startNumber + MESSAGE_COUNT;        for (int i = this.startNumber; i < this.endNumber; i++) {            TextMessage message = this.session.createTextMessage("I send the message " + i);            System.out.println(message.getText());            this.messageProducer.send(message);        }    }    /**     * 发送结束标志     *      * @param times     *            发送次数     * @throws JMSException     */    public void sendFinishMessage(int times) throws JMSException {        for (int i = 0; i < times; i++) {            TextMessage message = this.session.createTextMessage(ActivemqContants.FINISH_FLAG);            System.out.println("Send finish flag: " + message.getText());            this.messageProducer.send(message);        }    }    /**     * 提交事务     *      * @throws JMSException     */    public void commit() throws JMSException {        this.session.commit();    }}

        我写了两种消息消费者,其实也就是上一篇讲的同步消费和异步消费。

        先来看异步消费者:


package com.darren.activemq.queue;import javax.jms.JMSException;import javax.jms.Session;import com.darren.activemq.ProducerConsumer;import com.darren.activemq.listener.ConsumerListener;/** * 消息消费者 *  * @author Darren * */public class QueueListenerConsumer extends ProducerConsumer {    public QueueListenerConsumer(String name) throws JMSException {        this.name = name;        // 通过连接工厂获取连接        this.connection = this.getConnection();        // 启动连接        this.connection.start();        // 创建Session        this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE);        // 创建连接的消息队列        this.destination = this.session.createQueue("test-queue");        // 创建消息消费者        this.messageConsumer = this.session.createConsumer(destination);        // 设置消息监听        this.messageConsumer.setMessageListener(new ConsumerListener("Listener 1:", this));    }}

        异步消费者通过设置监听器来达到异步消费消息的目的。其实这个监听器也很简单,我们来看一下。

package com.darren.activemq.listener;import javax.jms.Message;import javax.jms.MessageListener;import javax.jms.ObjectMessage;import javax.jms.TextMessage;import com.darren.activemq.ActivemqContants;import com.darren.activemq.ProducerConsumer;/** * 消息监听 *  * @author Darren * */public class ConsumerListener implements MessageListener {    private String name;    private ProducerConsumer producerConsumer;    public ConsumerListener(String name, ProducerConsumer producerConsumer) {        this.name = name;        this.producerConsumer = producerConsumer;    }    @Override    public void onMessage(Message message) {        try {            if (message instanceof TextMessage) {                TextMessage textMessage = (TextMessage) message;                System.out.println(name + " 接收到的消息 " + textMessage.getText());                // 如果接收到结束标志,修改消费者的状态                if (ActivemqContants.FINISH_FLAG.equals(textMessage.getText())) {                    // 消费者消费完成,关闭连接                    this.producerConsumer.closeConnection();                }            } else if (message instanceof ObjectMessage) {                ObjectMessage objectMessage = (ObjectMessage) message;                System.out.println(name + " 接收到的消息 " + objectMessage.getObject());            } else {                System.out.println("不支持的消息类型!");            }        } catch (Exception e) {            e.printStackTrace();        }    }}

        这里只有一个方法。

        为了便于理解,我先把父类贴出来,这样就可以基本完整的看了。


package com.darren.activemq;import javax.jms.Connection;import javax.jms.ConnectionFactory;import javax.jms.Destination;import javax.jms.JMSException;import javax.jms.MessageConsumer;import javax.jms.MessageProducer;import javax.jms.Session;import org.apache.activemq.ActiveMQConnection;import org.apache.activemq.ActiveMQConnectionFactory;public abstract class ProducerConsumer {    protected static final String USERNAME = ActiveMQConnection.DEFAULT_USER;// 默认的连接用户名    protected static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;// 默认的连接密码    protected static final String BROKERURL = ActiveMQConnection.DEFAULT_BROKER_URL;// 默认的连接地址    protected static final int MESSAGE_COUNT = 10;// 发送的消息数量    protected static ConnectionFactory connectionFactory;// 连接工厂    protected Connection connection = null; // 连接    protected Session session;// 会话 接受或者发送消息的线程    protected Destination destination;// 消息的目的地    protected MessageProducer messageProducer;// 消息生产者    protected MessageConsumer messageConsumer;// 消息消费者    // 状态    protected volatile boolean isFinished = false;    protected String name;    static {        getConnectionFactory();    }    /**     * 获取连接工厂     *      * @return     */    protected synchronized static ConnectionFactory getConnectionFactory() {        if (connectionFactory == null) {            connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKERURL);        }        return connectionFactory;    }    /**     * 获取连接     *      * @return     * @throws JMSException     */    protected Connection getConnection() throws JMSException {        return connectionFactory.createConnection();    };    /**     * 关闭连接     *      * @throws JMSException     */    public void closeConnection() throws JMSException {        if (this.connection != null) {            this.connection.close();        }        System.out.println(this.name + " connection close!");        this.isFinished = true;    }    /**     * 获取状态     *      * @return     */    public boolean isFinished() {        return isFinished;    }    /**     * 获取消费者     *      * @return     */    public MessageConsumer getMessageConsumer() {        return messageConsumer;    }    /**     * 获取生产者或消费者名称     *      * @return     */    public String getName() {        return name;    }}

        用到的常量类

package com.darren.activemq;public class ActivemqContants {    public static final String FINISH_FLAG = "FINISHED";}


        来个测试类吧,这样就完整了

package com.darren.activemq.queue;import javax.jms.JMSException;public class QueueTest {    public static void main(String[] args) {        Thread thread = null;        try {            // 启动消费者,消费者开始等待            new QueueListenerConsumer("QueueListenerConsumer");            //new QueueReceiveConsumer("QueueReceiveConsumer");            thread = new Thread(new Runnable() {                @Override                public void run() {                    try {                        // 启动生产者,生产者定时生产消息                        QueueProducer producer = new QueueProducer("QueueProducer");                        Thread.sleep(2000);                        // 第一次发送                        producer.sendMessage();                        producer.commit();                        Thread.sleep(2000);                        // 第二次发送                        producer.sendMessage();                        producer.commit();                        Thread.sleep(2000);                        // 第三次发送                        producer.sendMessage();                        producer.commit();                        // 发送结束标志                        producer.sendFinishMessage(1);                        producer.commit();                        // 生产者生产完成,关闭连接                        producer.closeConnection();                    } catch (Exception e) {                        e.printStackTrace();                    }                }            });            thread.start();        } catch (JMSException e) {            e.printStackTrace();        }    }}


        现在为止,一个异步消息的完整例子就真的完整了,我是为了便于看到消息的消费过程,所以把生产者放到了一个线程里来不断的生产消息,来通过观察消费者打印的消费信息,了解消费的过程。


        再来看看同步消息模式:

        同步消费的方式就是轮训的去要有没有消息,有没有消息。为了适应我的测试类,我把同步消息消费也按照异步消费的模式做了相应的改动,下边就是代码:

package com.darren.activemq.queue;import javax.jms.JMSException;import javax.jms.Session;import com.darren.activemq.ProducerConsumer;import com.darren.activemq.listener.UglyConsumerListener;/** * 消息消费者 *  * @author Darren * */public class QueueReceiveConsumer extends ProducerConsumer {    public QueueReceiveConsumer(String name) throws JMSException {        this.name = name;        // 通过连接工厂获取连接        this.connection = this.getConnection();        // 启动连接        this.connection.start();        // 创建Session        this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE);        // 创建连接的消息队列        this.destination = this.session.createQueue("test-queue");        // 创建消息消费者        this.messageConsumer = this.session.createConsumer(destination);        // 启动一个异步线程接受消息,模拟一个消息监听器        Thread thread = new Thread(new UglyConsumerListener("UglyListener 1:", this));        thread.start();    }}


        在这里,我选择启动一个线程去设置一个监听器,为什么要启动线程,因为我上边提到了要适应我的测试类,我是先初始化消费者,如果不用线程,那么消费者就会在要消息的时候夯住,因为:

Message message = messageConsumer.receive(100000);


        这个方法是阻塞式方法。会程序在初始化消费者后就会夯住,然后生成者无法启动,无法生成消息,整个程序就死锁了,为了解决这个问题,所以采用模拟异步消费的方式来写同步消费例子。

        下边来看我写的丑陋的监听器:

package com.darren.activemq.listener;import javax.jms.JMSException;import javax.jms.Message;import javax.jms.MessageConsumer;import javax.jms.ObjectMessage;import javax.jms.TextMessage;import com.darren.activemq.ActivemqContants;import com.darren.activemq.ProducerConsumer;/** * 消息监听 *  * @author Darren * */public class UglyConsumerListener implements Runnable {    private String name;    private ProducerConsumer producerConsumer;    public UglyConsumerListener(String name, ProducerConsumer producerConsumer) {        this.name = name;        this.producerConsumer = producerConsumer;    }    public void onMessage(Message message) {        try {            if (message instanceof TextMessage) {                TextMessage textMessage = (TextMessage) message;                System.out.println(name + " 接收到的消息 " + textMessage.getText());                // 如果接收到结束标志,修改消费者的状态                if (ActivemqContants.FINISH_FLAG.equals(textMessage.getText())) {                    // 消费者消费完成,关闭连接                    this.producerConsumer.closeConnection();                }            } else if (message instanceof ObjectMessage) {                ObjectMessage objectMessage = (ObjectMessage) message;                System.out.println(name + " 接收到的消息 " + objectMessage.getObject());            } else {                System.out.println("不支持的消息类型!");            }        } catch (Exception e) {            e.printStackTrace();        }    }    @Override    public void run() {        while (!producerConsumer.isFinished()) {            MessageConsumer messageConsumer = this.producerConsumer.getMessageConsumer();            if (messageConsumer != null) {                try {                    Message message = messageConsumer.receive(100000);                    this.onMessage(message);                } catch (JMSException e) {                    e.printStackTrace();                }            }        }    }}

        为什么称为丑陋的监听器,相信大家也不难发现,因为采用循环方式,并不是真正的监听器。 看了这两个监听器,那么我提出一个问题,这个问题也是在我写这篇文章的时候发现的,如果我再写一个抽象类去作为这两个监听器的父类,把onMessage方法提出来,是不是更加优化了,因为我发现两个onMessage方法其实一样,我也是故意给做的一样的。

        当然今天讲的并不是Java的重构,而是JMS,这个问题就作为题外话好了。


        现在你自己也可以去跑一跑这两个例子,细心的同学或发现在测试类中其实有一行有疑问。为什么发送结束消息的方法要加参数,可以设置发送多个结束消息。这个问题我们稍后介绍,下面我来运行一下代码,也许你就渐渐明白。


        先跑一个异步消费的例子:


 INFO | Successfully connected to tcp://localhost:61616 INFO | Successfully connected to tcp://localhost:61616I send the message 0I send the message 1I send the message 2I send the message 3I send the message 4I send the message 5I send the message 6I send the message 7I send the message 8I send the message 9Listener 1: 接收到的消息 I send the message 0Listener 1: 接收到的消息 I send the message 1Listener 1: 接收到的消息 I send the message 2Listener 1: 接收到的消息 I send the message 3Listener 1: 接收到的消息 I send the message 4Listener 1: 接收到的消息 I send the message 5Listener 1: 接收到的消息 I send the message 6Listener 1: 接收到的消息 I send the message 7Listener 1: 接收到的消息 I send the message 8Listener 1: 接收到的消息 I send the message 9I send the message 10I send the message 11I send the message 12I send the message 13I send the message 14I send the message 15I send the message 16I send the message 17I send the message 18I send the message 19Listener 1: 接收到的消息 I send the message 10Listener 1: 接收到的消息 I send the message 11Listener 1: 接收到的消息 I send the message 12Listener 1: 接收到的消息 I send the message 13Listener 1: 接收到的消息 I send the message 14Listener 1: 接收到的消息 I send the message 15Listener 1: 接收到的消息 I send the message 16Listener 1: 接收到的消息 I send the message 17Listener 1: 接收到的消息 I send the message 18Listener 1: 接收到的消息 I send the message 19I send the message 20I send the message 21I send the message 22I send the message 23I send the message 24I send the message 25I send the message 26I send the message 27I send the message 28I send the message 29Listener 1: 接收到的消息 I send the message 20Listener 1: 接收到的消息 I send the message 21Send finish flag: FINISHEDListener 1: 接收到的消息 I send the message 22Listener 1: 接收到的消息 I send the message 23Listener 1: 接收到的消息 I send the message 24Listener 1: 接收到的消息 I send the message 25Listener 1: 接收到的消息 I send the message 26Listener 1: 接收到的消息 I send the message 27Listener 1: 接收到的消息 I send the message 28Listener 1: 接收到的消息 I send the message 29Listener 1: 接收到的消息 FINISHEDQueueProducer connection close!QueueListenerConsumer connection close!

        然后再来跑一个同步消费的例子:

            //new QueueListenerConsumer("QueueListenerConsumer");            new QueueReceiveConsumer("QueueReceiveConsumer");

        只需把注水换一换就行了。

 INFO | Successfully connected to tcp://localhost:61616 INFO | Successfully connected to tcp://localhost:61616I send the message 0I send the message 1I send the message 2I send the message 3I send the message 4I send the message 5I send the message 6I send the message 7I send the message 8I send the message 9UglyListener 1: 接收到的消息 I send the message 0UglyListener 1: 接收到的消息 I send the message 1UglyListener 1: 接收到的消息 I send the message 2UglyListener 1: 接收到的消息 I send the message 3UglyListener 1: 接收到的消息 I send the message 4UglyListener 1: 接收到的消息 I send the message 5UglyListener 1: 接收到的消息 I send the message 6UglyListener 1: 接收到的消息 I send the message 7UglyListener 1: 接收到的消息 I send the message 8UglyListener 1: 接收到的消息 I send the message 9I send the message 10I send the message 11I send the message 12I send the message 13I send the message 14I send the message 15I send the message 16I send the message 17I send the message 18I send the message 19UglyListener 1: 接收到的消息 I send the message 10UglyListener 1: 接收到的消息 I send the message 11UglyListener 1: 接收到的消息 I send the message 12UglyListener 1: 接收到的消息 I send the message 13UglyListener 1: 接收到的消息 I send the message 14UglyListener 1: 接收到的消息 I send the message 15UglyListener 1: 接收到的消息 I send the message 16UglyListener 1: 接收到的消息 I send the message 17UglyListener 1: 接收到的消息 I send the message 18UglyListener 1: 接收到的消息 I send the message 19I send the message 20I send the message 21I send the message 22I send the message 23I send the message 24I send the message 25I send the message 26I send the message 27I send the message 28I send the message 29Send finish flag: FINISHEDUglyListener 1: 接收到的消息 I send the message 20UglyListener 1: 接收到的消息 I send the message 21UglyListener 1: 接收到的消息 I send the message 22UglyListener 1: 接收到的消息 I send the message 23UglyListener 1: 接收到的消息 I send the message 24UglyListener 1: 接收到的消息 I send the message 25UglyListener 1: 接收到的消息 I send the message 26UglyListener 1: 接收到的消息 I send the message 27UglyListener 1: 接收到的消息 I send the message 28UglyListener 1: 接收到的消息 I send the message 29UglyListener 1: 接收到的消息 FINISHEDQueueReceiveConsumer connection close!QueueProducer connection close!

        大家会发现和异步消费并未区别,因为其实也是异步消费。

        那么如果我现在把测试类的注释都打开,会是什么结果呢:

new QueueListenerConsumer("QueueListenerConsumer");new QueueReceiveConsumer("QueueReceiveConsumer");

 INFO | Successfully connected to tcp://localhost:61616 INFO | Successfully connected to tcp://localhost:61616 INFO | Successfully connected to tcp://localhost:61616I send the message 0I send the message 1I send the message 2I send the message 3I send the message 4I send the message 5I send the message 6I send the message 7I send the message 8I send the message 9Listener 1: 接收到的消息 I send the message 0Listener 1: 接收到的消息 I send the message 2UglyListener 1: 接收到的消息 I send the message 1Listener 1: 接收到的消息 I send the message 4Listener 1: 接收到的消息 I send the message 6Listener 1: 接收到的消息 I send the message 8UglyListener 1: 接收到的消息 I send the message 3UglyListener 1: 接收到的消息 I send the message 5UglyListener 1: 接收到的消息 I send the message 7UglyListener 1: 接收到的消息 I send the message 9I send the message 10I send the message 11I send the message 12I send the message 13I send the message 14I send the message 15I send the message 16I send the message 17I send the message 18I send the message 19Listener 1: 接收到的消息 I send the message 10Listener 1: 接收到的消息 I send the message 12Listener 1: 接收到的消息 I send the message 14UglyListener 1: 接收到的消息 I send the message 11Listener 1: 接收到的消息 I send the message 16UglyListener 1: 接收到的消息 I send the message 13Listener 1: 接收到的消息 I send the message 18UglyListener 1: 接收到的消息 I send the message 15UglyListener 1: 接收到的消息 I send the message 17UglyListener 1: 接收到的消息 I send the message 19I send the message 20I send the message 21I send the message 22I send the message 23I send the message 24I send the message 25I send the message 26I send the message 27I send the message 28I send the message 29Listener 1: 接收到的消息 I send the message 20Listener 1: 接收到的消息 I send the message 22Listener 1: 接收到的消息 I send the message 24Listener 1: 接收到的消息 I send the message 26Listener 1: 接收到的消息 I send the message 28Send finish flag: FINISHEDUglyListener 1: 接收到的消息 I send the message 21UglyListener 1: 接收到的消息 I send the message 23UglyListener 1: 接收到的消息 I send the message 25UglyListener 1: 接收到的消息 I send the message 27UglyListener 1: 接收到的消息 I send the message 29Listener 1: 接收到的消息 FINISHEDQueueProducer connection close!QueueListenerConsumer connection close!

        这个时候有俩个消费者,一个消费者消费了一半的消息,这里我没有深入研究这种消费平均的方式是随机的还是真的平均,我猜猜可能是真的平均,因为我运行了多次都是同样的结果。

        通过我打出来的消息,发现只有一个消费者结束了,另一个并没有结束,因为没有收到结束消息标志,所以需要发送两个结束标志才能使两个消费者都能结束。

producer.sendFinishMessage(2);

        这也正是我设置参数的原因:

        改成2之后再来运行一次:

 INFO | Successfully connected to tcp://localhost:61616 INFO | Successfully connected to tcp://localhost:61616 INFO | Successfully connected to tcp://localhost:61616I send the message 0I send the message 1I send the message 2I send the message 3I send the message 4I send the message 5I send the message 6I send the message 7I send the message 8I send the message 9Listener 1: 接收到的消息 I send the message 0Listener 1: 接收到的消息 I send the message 2UglyListener 1: 接收到的消息 I send the message 1Listener 1: 接收到的消息 I send the message 4UglyListener 1: 接收到的消息 I send the message 3Listener 1: 接收到的消息 I send the message 6UglyListener 1: 接收到的消息 I send the message 5Listener 1: 接收到的消息 I send the message 8UglyListener 1: 接收到的消息 I send the message 7UglyListener 1: 接收到的消息 I send the message 9I send the message 10I send the message 11I send the message 12I send the message 13I send the message 14I send the message 15I send the message 16I send the message 17I send the message 18I send the message 19Listener 1: 接收到的消息 I send the message 10Listener 1: 接收到的消息 I send the message 12Listener 1: 接收到的消息 I send the message 14Listener 1: 接收到的消息 I send the message 16Listener 1: 接收到的消息 I send the message 18UglyListener 1: 接收到的消息 I send the message 11UglyListener 1: 接收到的消息 I send the message 13UglyListener 1: 接收到的消息 I send the message 15UglyListener 1: 接收到的消息 I send the message 17UglyListener 1: 接收到的消息 I send the message 19I send the message 20I send the message 21I send the message 22I send the message 23I send the message 24I send the message 25I send the message 26I send the message 27I send the message 28I send the message 29Listener 1: 接收到的消息 I send the message 20Listener 1: 接收到的消息 I send the message 22Listener 1: 接收到的消息 I send the message 24Listener 1: 接收到的消息 I send the message 26Listener 1: 接收到的消息 I send the message 28Send finish flag: FINISHEDSend finish flag: FINISHEDUglyListener 1: 接收到的消息 I send the message 21UglyListener 1: 接收到的消息 I send the message 23UglyListener 1: 接收到的消息 I send the message 25UglyListener 1: 接收到的消息 I send the message 27UglyListener 1: 接收到的消息 I send the message 29Listener 1: 接收到的消息 FINISHEDUglyListener 1: 接收到的消息 FINISHEDQueueProducer connection close!QueueReceiveConsumer connection close!QueueListenerConsumer connection close!

        现在两个消费者都正常结束了。到此我的点对点模式就介绍完了。


订阅/发布模式


        生产者:

package com.darren.activemq.topic;import javax.jms.JMSException;import javax.jms.Session;import javax.jms.TextMessage;import com.darren.activemq.ActivemqContants;import com.darren.activemq.ProducerConsumer;public class TopicProducer extends ProducerConsumer {    private int startNumber;    private int endNumber;    public TopicProducer(String name) throws JMSException {        this.name = name;        // 通过连接工厂获取连接        this.connection = this.getConnection();        // 启动连接        this.connection.start();        // 创建Session        this.session = this.connection.createSession(true, Session.AUTO_ACKNOWLEDGE);        // 创建消息队列        this.destination = this.session.createTopic("test-topic");        // 创建消息生产者        this.messageProducer = this.session.createProducer(destination);    }    /**     * 发送消息     *      * @throws JMSException     */    public void sendMessage() throws JMSException {        this.startNumber = this.endNumber;        this.endNumber = this.startNumber + MESSAGE_COUNT;        for (int i = this.startNumber; i < this.endNumber; i++) {            TextMessage message = this.session.createTextMessage("I send the message " + i);            System.out.println(message.getText());            this.messageProducer.send(message);        }    }    /**     * 发送结束标志     *      * @throws JMSException     */    public void sendFinishMessage() throws JMSException {        TextMessage message = this.session.createTextMessage(ActivemqContants.FINISH_FLAG);        System.out.println("Send finish flag: " + message.getText());        this.messageProducer.send(message);    }    /**     * 提交事务     *      * @throws JMSException     */    public void commit() throws JMSException {        this.session.commit();    }}

        消费者:

package com.darren.activemq.topic;import javax.jms.JMSException;import javax.jms.Session;import com.darren.activemq.ProducerConsumer;import com.darren.activemq.listener.ConsumerListener;public class TopicListenerConsumer extends ProducerConsumer {    public TopicListenerConsumer(String name) throws JMSException {        this.name = name;        // 通过连接工厂获取连接        this.connection = this.getConnection();        // 启动连接        this.connection.start();        // 创建Session        this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE);        // 创建连接的消息队列        this.destination = this.session.createTopic("test-topic");        // 创建消息消费者        this.messageConsumer = this.session.createConsumer(destination);        // 设置消息监听        this.messageConsumer.setMessageListener(new ConsumerListener("Listener 1:", this));    }}

package com.darren.activemq.topic;import javax.jms.JMSException;import javax.jms.Session;import com.darren.activemq.ProducerConsumer;import com.darren.activemq.listener.UglyConsumerListener;public class TopicReceiveConsumer extends ProducerConsumer {    public TopicReceiveConsumer(String name) throws JMSException {        this.name = name;        // 通过连接工厂获取连接        this.connection = this.getConnection();        // 启动连接        this.connection.start();        // 创建Session        this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE);        // 创建连接的消息队列        this.destination = this.session.createTopic("test-topic");        // 创建消息消费者        this.messageConsumer = this.session.createConsumer(destination);        // 启动一个异步线程接受消息,模拟一个消息监听器        Thread thread = new Thread(new UglyConsumerListener("UglyListener 1:", this));        thread.start();    }}

        大家可以看出相比点对点模式的例子,消息的订阅/发布模式只做了很小的改动:

this.destination = this.session.createQueue("test-queue");//改成this.destination = this.session.createTopic("test-topic");

        其他代码都重用了,接下来是测试类:

package com.darren.activemq.topic;import javax.jms.JMSException;public class TopicTest {    public static void main(String[] args) {        Thread thread = null;        try {            // 启动消费者,消费者开始等待            new TopicListenerConsumer("TopicListenerConsumer");            new TopicReceiveConsumer("TopicReceiveConsumer");            thread = new Thread(new Runnable() {                @Override                public void run() {                    try {                        // 启动生产者,生产者定时生产消息                        TopicProducer producer = new TopicProducer("TopicProducer");                        Thread.sleep(2000);                        // 第一次发送                        producer.sendMessage();                        producer.commit();                        Thread.sleep(2000);                        // 第二次发送                        producer.sendMessage();                        producer.commit();                        Thread.sleep(2000);                        // 第三次发送                        producer.sendMessage();                        producer.commit();                        // 发送结束标志                        producer.sendFinishMessage();                        producer.commit();                        // 生产者生产完成,关闭连接                        producer.closeConnection();                    } catch (Exception e) {                        e.printStackTrace();                    }                }            });            thread.start();        } catch (JMSException e) {            e.printStackTrace();        }    }}

        运行这个例子:

 INFO | Successfully connected to tcp://localhost:61616 INFO | Successfully connected to tcp://localhost:61616 INFO | Successfully connected to tcp://localhost:61616I send the message 0I send the message 1I send the message 2I send the message 3I send the message 4I send the message 5I send the message 6I send the message 7I send the message 8I send the message 9Listener 1: 接收到的消息 I send the message 0Listener 1: 接收到的消息 I send the message 1UglyListener 1: 接收到的消息 I send the message 0Listener 1: 接收到的消息 I send the message 2UglyListener 1: 接收到的消息 I send the message 1Listener 1: 接收到的消息 I send the message 3Listener 1: 接收到的消息 I send the message 4UglyListener 1: 接收到的消息 I send the message 2Listener 1: 接收到的消息 I send the message 5UglyListener 1: 接收到的消息 I send the message 3Listener 1: 接收到的消息 I send the message 6Listener 1: 接收到的消息 I send the message 7UglyListener 1: 接收到的消息 I send the message 4Listener 1: 接收到的消息 I send the message 8UglyListener 1: 接收到的消息 I send the message 5Listener 1: 接收到的消息 I send the message 9UglyListener 1: 接收到的消息 I send the message 6UglyListener 1: 接收到的消息 I send the message 7UglyListener 1: 接收到的消息 I send the message 8UglyListener 1: 接收到的消息 I send the message 9I send the message 10I send the message 11I send the message 12I send the message 13I send the message 14I send the message 15I send the message 16I send the message 17I send the message 18I send the message 19Listener 1: 接收到的消息 I send the message 10Listener 1: 接收到的消息 I send the message 11Listener 1: 接收到的消息 I send the message 12Listener 1: 接收到的消息 I send the message 13Listener 1: 接收到的消息 I send the message 14Listener 1: 接收到的消息 I send the message 15Listener 1: 接收到的消息 I send the message 16Listener 1: 接收到的消息 I send the message 17Listener 1: 接收到的消息 I send the message 18Listener 1: 接收到的消息 I send the message 19UglyListener 1: 接收到的消息 I send the message 10UglyListener 1: 接收到的消息 I send the message 11UglyListener 1: 接收到的消息 I send the message 12UglyListener 1: 接收到的消息 I send the message 13UglyListener 1: 接收到的消息 I send the message 14UglyListener 1: 接收到的消息 I send the message 15UglyListener 1: 接收到的消息 I send the message 16UglyListener 1: 接收到的消息 I send the message 17UglyListener 1: 接收到的消息 I send the message 18UglyListener 1: 接收到的消息 I send the message 19I send the message 20I send the message 21I send the message 22I send the message 23I send the message 24I send the message 25I send the message 26I send the message 27I send the message 28I send the message 29Listener 1: 接收到的消息 I send the message 20Listener 1: 接收到的消息 I send the message 21Listener 1: 接收到的消息 I send the message 22Listener 1: 接收到的消息 I send the message 23Listener 1: 接收到的消息 I send the message 24Listener 1: 接收到的消息 I send the message 25Listener 1: 接收到的消息 I send the message 26Listener 1: 接收到的消息 I send the message 27Send finish flag: FINISHEDUglyListener 1: 接收到的消息 I send the message 20UglyListener 1: 接收到的消息 I send the message 21Listener 1: 接收到的消息 I send the message 28UglyListener 1: 接收到的消息 I send the message 22Listener 1: 接收到的消息 I send the message 29UglyListener 1: 接收到的消息 I send the message 23UglyListener 1: 接收到的消息 I send the message 24UglyListener 1: 接收到的消息 I send the message 25UglyListener 1: 接收到的消息 I send the message 26Listener 1: 接收到的消息 FINISHEDUglyListener 1: 接收到的消息 I send the message 27UglyListener 1: 接收到的消息 I send the message 28UglyListener 1: 接收到的消息 I send the message 29UglyListener 1: 接收到的消息 FINISHEDTopicListenerConsumer connection close!TopicReceiveConsumer connection close!TopicProducer connection close!

        两个订阅者获取的消息一模一样,并不是平半分了消息,这就是订阅/发布与点对点的不同。

        注:订阅/发布模式必须要先订阅,这样订阅者才能收到消息。





原创粉丝点击