点对点消息传送模型允许JMS客户端通过队列(Queue)这个虚拟通道来同步和异步发送、接收消息。消息的生产者成为QueueSender,消费者为QueueReceiver。点对点模型是一个基于拉取(pull,即receive方式)或者基于轮询(polling,即异步接收)的消息传输模型,这种模型从队列中请求消息,而不是JMS Provider将消息自动的推送给客户端。发送到队列的消息,将会被一个而且仅仅一个消费者接收,即使有多个消费者侦听同一个队列。
点对点消息传送模型,即支持异步“即发即弃”,又支持同步的“请求--应答”的消息发送方式。(稍后代码实例)
点对点模型支持负载均衡,即多个消息消费者侦听同一个队列时,JMS Provider负责将这些消息以"某种策略"均衡的分发给它们.事实上点对点模型的负载均衡很容易实现,因为消息消费者只有处于"空闲时"才会向JMS Provider"索取"消息.对于Queue,还提供了使用Browser的方式查看队列消息而不消费它们.
点对点消息模型,对于JMS Provider而言,就是一个队列,JMS Provider将会对消息按照其发送到队列的顺序排序.然后依次发送给消费者(权重优先),一旦消息被消费者接收(确认),消息将会从队列中移除.
不过需要特殊强调一点:JMS Prodiver并不是严格的保证队列中消息移除的顺序,特别是在多个消费者Client时;当多个消费者同时侦听消息队列,JMS Prodiver将会把队列中的消息,依次转发给各个Client,此时如果消息被接收且确认,消息将会从队列中移除,此消息有可能并不是队列的第一个元素;当一个消息未能确认时,JMS Provider会将此消息不断的重发,直到重发次数达到阀值;一条消息不能正确接收,这种情况不会影响到队列中其他消息的正常消费;而且由于网络的问题,优先发送的消息,可能在消费者接收的时间上滞后.由此可见,依靠Queue来完全实现消息的队列化消费是错误的.(理想的情况是,一个消息接收确认之后,队列中此后的消息才会被发送给消费者).
你可以简单的认为P2P消息模型的存储机制为:
+++++++++++++++ ++MessageId | Created | Priority++ ++100 100000000000 3 ++101 100000002000 3 ++102 100000004000 2
对于消息的发送顺序为"order by priority des,created asc",一旦发送成功,将会delete.
点对点消息传送模型有两种:
1) 即发即弃: 一种异步的消息发送和确认机制,Producer发送消息之后,它无需等待此消息被消费的"响应".
2) 请求-应答: 一种同步机制,Producer发送消息之后,它阻塞,直到此消息被消费;当消息被消费时,将会向一个"响应队列"中发送一个"通知",那么对于Producer而言,就是接收到这个"通知后"才会返回.
###contextFactory java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory ###brokerUrl,any protocol java.naming.provider.url = tcp://localhost:61616 ##username ##java.naming.security.principal= ##password ##java.naming.security.credentials= ##connectionFactory,for building sessions connectionFactoryNames = QueueCF,TopicCF ##topic.<topicName> = <physicalName-of-topic> ##your application should use <topicName>,such as: ## context.lookup("topic1"); ##It can be more than once topic.topic1 = jms.topic1 ##queue.<topicName> = <physicalName-of-queue> queue.queue1 = jms.queue1
///请求应答模式:生产者 package com.test.jms.simple; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.DeliveryMode; import javax.jms.Destination; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.QueueConnectionFactory; import javax.jms.QueueReceiver; import javax.jms.Session; import javax.naming.Context; import javax.naming.InitialContext; public class SimpleProductor { private MessageProducer producer; private Session session; private Connection connection; private boolean isOpen = true; private Destination replyTo; public SimpleProductor() throws Exception{ Context context = new InitialContext(); ConnectionFactory connectionFactory = (QueueConnectionFactory)context.lookup("QueueCF"); connection = connectionFactory.createConnection(); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination queue = (Queue)context.lookup("queue1"); replyTo = (Queue)context.lookup("test-repyto"); producer = session.createProducer(queue); producer.setDeliveryMode(DeliveryMode.PERSISTENT); connection.start(); } public boolean send(String text) { if(!isOpen){ throw new RuntimeException("session has been closed!"); } try{ Message message = session.createTextMessage(text); String cid = "ID:" + System.currentTimeMillis(); message.setJMSCorrelationID(cid); producer.send(message); MessageConsumer consumer = session.createConsumer(replyTo,"JMSCorrelationID='" + cid + "'"); //最多重发5次 for(int i=0;i< 5;i++){ Message replyMessage = consumer.receive(30000); if(replyMessage != null){ System.out.println("Reply success:" + replyMessage.getJMSCorrelationID()); break; } } consumer.close(); return true; }catch(Exception e){ return false; } } public synchronized void close(){ try{ if(isOpen){ isOpen = false; } session.close(); connection.close(); }catch (Exception e) { // } } }
//请求应答模式:消费者 package com.test.jms.simple; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.MessageConsumer; import javax.jms.Queue; import javax.jms.QueueConnectionFactory; import javax.jms.Session; import javax.naming.Context; import javax.naming.InitialContext; import com.test.jms.object.QueueMessageListener; public class SimpleConsumer { private Connection connection; private Session session; private MessageConsumer consumer; private boolean isStarted; public SimpleConsumer() throws Exception{ Context context = new InitialContext(); ConnectionFactory connectionFactory = (QueueConnectionFactory)context.lookup("QueueCF"); connection = connectionFactory.createConnection(); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination queue = (Queue)context.lookup("queue1"); consumer = session.createConsumer(queue); consumer.setMessageListener(new QueueMessageListener(session)); connection.start(); } public synchronized boolean start(){ if(isStarted){ return true; } try{ connection.start(); isStarted = true; return true; }catch(Exception e){ return false; } } public synchronized void close(){ isStarted = false; try{ session.close(); connection.close(); }catch(Exception e){ // } } }
///请求应答模式:消息侦听器 package com.test.jms.object; import javax.jms.DeliveryMode; import javax.jms.Destination; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; public class QueueMessageListener implements MessageListener{ private Session session; public QueueMessageListener(Session session){ this.session = session; } public void onMessage(Message message) { if(message == null){ return; } try{ Destination replyTo = message.getJMSReplyTo(); if(message instanceof TextMessage){ String text = ((TextMessage)message).getText(); System.out.println(text); } if(replyTo != null){ message.clearBody(); MessageProducer producer = session.createProducer(replyTo); producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); producer.setTimeToLive(50000); producer.send(message); producer.close(); } }catch(Exception e){ e.printStackTrace(); } } }