今天的Demo演示了点对点模型中消息发送者与消息消费者在传递消息时的两种方式,一种是不管消息队列中有没有消息,消费者一直在取;一种是监听消息队列,当有消息时才取.
首先开启服务,我这里用的是Activemq,运行相应的bat文件即可.在浏览器访问http://localhost:8161/,看到欢迎界面代表成功.
第一种:消费者直接取
package com.tgb.activemq; 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 ghy * */ public class QueueSender { private static final String USERNAME=ActiveMQConnectionFactory.DEFAULT_USER;//默认的连接用户名 private static final String PASSWORD=ActiveMQConnectionFactory.DEFAULT_PASSWORD;//默认的连接密码 private static final String BROKEURL=ActiveMQConnectionFactory.DEFAULT_BROKER_URL;//默认的连接地址 private static final int SENDNUM=10;//发送的消息数量 public static void main(String[] args){ ConnectionFactory connectionFactory;//连接工厂 Connection connection=null; //连接 Session session; //会话,接受或者发送消息的线程 Destination destination; //消息的目的地 MessageProducer messageProducer; //消息发送者 //实例化连接工厂 connectionFactory=new ActiveMQConnectionFactory(QueueSender.USERNAME,QueueSender.PASSWORD,QueueSender.BROKEURL); try { connection=connectionFactory.createConnection();//创建连接 connection.start();//启动连接 session=connection.createSession(true, Session.AUTO_ACKNOWLEDGE);//创建连接 destination=session.createQueue("FirstQueue1");//创建消息队列 messageProducer=session.createProducer(destination);//创建消息生产者 sendMessage(session,messageProducer); session.commit(); } catch (Exception e) { e.printStackTrace(); }finally{ if(connection!=null){ try { connection.close(); } catch (JMSException e) { e.printStackTrace(); } } } } public static void sendMessage(Session session,MessageProducer messageProducer){ for (int i=0;i<QueueSender.SENDNUM;i++){ TextMessage message; try { message = session.createTextMessage("ActiveMQ 发送的消息" + i); System.out.println("发送消息:" + "ActiveMQ 发送的消息" + i); messageProducer.send(message); } catch (JMSException e) { e.printStackTrace(); } } } }
QueueSender发送消息后的运行结果:
通过控制台可以看到消息队列中的消息数目及入队(生产)和出列(消费)情况.
package com.tgb.activemq; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; /** * 消息消费者 * @author ghy * */ public class QueueReceiver { private static final String USERNAME=ActiveMQConnection.DEFAULT_USER;//默认连接的用户名 private static final String PASSWORD=ActiveMQConnection.DEFAULT_PASSWORD;//默认连接密码 private static final String BROKEURL=ActiveMQConnection.DEFAULT_BROKER_URL;//默认链接地址 public static void main(String[] args){ ConnectionFactory connectionFactory;//连接工厂 Connection connection=null;//连接 Session session;//会话 Destination destination;//目的地 MessageConsumer messageConsumer;//消息消费者 connectionFactory=new ActiveMQConnectionFactory(QueueReceiver.USERNAME,QueueReceiver.PASSWORD,QueueReceiver.BROKEURL); try { connection=connectionFactory.createConnection();//创建连接 connection.start();//启动连接 session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE);//创建session destination=session.createQueue("FirstQueue1");//创建连接的消息队列 messageConsumer=session.createConsumer(destination);//创建消息消费者 while(true){ TextMessage textMessage=(TextMessage) messageConsumer.receive();//接收消息 if(textMessage!=null){ System.out.println("收到的消息:" + textMessage.getText()); }else{ break; } } } catch (JMSException e) { e.printStackTrace(); } } }
QueueReceiver接收消息后的运行结果:
可以看到已经生产的10条消息已经被现在的这个消费者消费了.
第二种:使用监听的方式
再次运行QueueSender,发送10条消息,运行结果和控制台显示同上.
package com.tgb.activemq; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; /** * 消息消费者 * @author ghy * */ public class QueueReceiver2 { private static final String USERNAME=ActiveMQConnection.DEFAULT_USER;//默认连接的用户名 private static final String PASSWORD=ActiveMQConnection.DEFAULT_PASSWORD;//默认连接密码 private static final String BROKEURL=ActiveMQConnection.DEFAULT_BROKER_URL;//默认链接地址 public static void main(String[] args){ ConnectionFactory connectionFactory;//连接工厂 Connection connection=null;//连接 Session session;//会话 Destination destination;//目的地 MessageConsumer messageConsumer;//消息消费者 connectionFactory=new ActiveMQConnectionFactory(QueueReceiver2.USERNAME,QueueReceiver2.PASSWORD,QueueReceiver2.BROKEURL); try { connection=connectionFactory.createConnection();//创建连接 connection.start();//启动连接 session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE);//创建session destination=session.createQueue("FirstQueue1");//创建连接的消息队列 messageConsumer=session.createConsumer(destination);//创建消息消费者 messageConsumer.setMessageListener(new Listener());//注册监听器 } catch (JMSException e) { e.printStackTrace(); } } }
监听器:
package com.tgb.activemq; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; /** * 监听器 * @author ghy * */ public class Listener implements MessageListener { public void onMessage(Message message) { try { System.out.println("收到的消息:" + ((TextMessage)message).getText()); } catch (JMSException e) { e.printStackTrace(); } } }
QueueReceiver2接收消息后的运行结果:
可以看到刚刚生产的10条消息已经被消费者QueueReceiver2消费了.
======================================================================================
接下来我对2个接收者同时接收消息做了测试,纯属测试结果如下.
再次发送10条消息:
QueueReceiver接收了5条:
QueueReceiver2接收了5条:
我们不要被这个均分的现象迷惑了,在这种情况下,多个消息消费者同时接收消息时,什么时候接收到,接收到多少条是不确定的.但是在实际应用中,消息生产者要发送消息给哪个消息消费者是确定的,就像我们要给人写信,收信人是确定的,而不是写完就寄出去了,信被送到哪算哪.