深入掌握JMS(一):JSM基础

1. JMS基本概念
     JMS(Java Message Service) 即Java消息服务。它提供标准的产生、发送、接收消息的接口简化企业应用的开发。它支持两种消息通信模型:点到点(point-to-point)(P2P)模型和发布/订阅(Pub/Sub)模型。P2P 模型规定了一个消息只能有一个接收者;Pub/Sub 模型允许一个消息可以有多个接收者。
    对于点到点模型,消息生产者产生一个消息后,把这个消息发送到一个Queue(队列)中,然后消息接收者再从这个Queue中读取,一旦这个消息被一个接收者读取之后,它就在这个Queue中消失了,所以一个消息只能被一个接收者消费。
    与点到点模型不同,发布/订阅模型中,消息生产者产生一个消息后,把这个消息发送到一个Topic中,这个Topic可以同时有多个接收者在监听,当一个消息到达这个Topic之后,所有消息接收者都会收到这个消息。

简单的讲,点到点模型和发布/订阅模型的区别就是前者是一对一,后者是一对多。

2. 几个重要概念 
   Destination :消息发送的目的地,也就是前面说的Queue和Topic。创建好一个消息之后,只需要把这个消息发送到目的地,消息的发送者就可以继续做自己的事情,而不用等待消息被处理完成。至于这个消息什么时候,会被哪个消费者消费,完全取决于消息的接受者。
    Message :从字面上就可以看出是被发送的消息。它有下面几种类型:
        StreamMessage:Java 数据流消息,用标准流操作来顺序的填充和读取。
        MapMessage:一个Map类型的消息;名称为 string 类型,而值为 Java 的基本类型。
        TextMessage:普通字符串消息,包含一个String。
        ObjectMessage:对象消息,包含一个可序列化的Java 对象
        BytesMessage:二进制数组消息,包含一个byte[]。
        XMLMessage:  一个XML类型的消息。
    最常用的是TextMessage和ObjectMessage。
   Session: 与JMS提供者所建立的会话,通过Session我们才可以创建一个Message。
   Connection: 与JMS提供者建立的一个连接。可以从这个连接创建一个会话,即Session。
   ConnectionFactory: 那如何创建一个Connection呢?这就需要下面讲到的ConnectionFactory了。通过这个工厂类就可以得到一个与JMS提供者的连接,即Conection。
   Producer: 消息的生产者,要发送一个消息,必须通过这个生产者来发送。
   MessageConsumer: 与生产者相对应,这是消息的消费者或接收者,通过它来接收一个消息。
   前面多次提到JMS提供者,因为JMS给我们提供的只是一系列接口,当我们使用一个JMS的时候,还是需要一个第三方的提供者,它的作用就是真正管理这些Connection,Session,Topic和Queue等。

通过下面这个简图可以看出上面这些概念的关系。

ConnectionFactory---->Connection--->Session--->Message
  Destination + Session------------------------------------>Producer
  Destination + Session------------------------------------>MessageConsumer 
 
    那么可能有人会问: ConnectionFactory和Destination 从哪儿得到?
    这就和JMS提供者有关了. 如果在一个JavaEE环境中, 可以通过JNDI查找得到, 如果在一个非JavaEE环境中, 那只能通过JMS提供者提供给我们的接口得到了.

深入掌握JMS(二):一个JMS例子

前一讲简单的介绍了一下JMS的基本概念, 这一讲结合一个例子让大家深入理解前一讲的基本概念. 首先需要做的是选择一个JMS提供者, 如果在JavaEE环境中可以不用考虑这些. 我们选择ActiveMQ, 官方地址: http://activemq.apache.org/. 网上有很多介绍ActiveMQ的文档, 所以在这里就不介绍了.

按照上一讲的这个简图,

ConnectionFactory---->Connection--->Session--->Message
  Destination + Session------------------------------------>Producer
  Destination + Session------------------------------------>MessageConsumer

首先需要得到ConnectionFactoy和Destination,这里创建一个一对一的Queue作为Destination。
  ConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost");
  Queue queue = new ActiveMQQueue("testQueue");

然后又ConnectionFactory创建一个Connection, 再启动这个Connection:
  Connection connection = factory.createConnection();
  connection.start();

接下来需要由Connection创建一个Session:
  Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)
    现在暂且不用管参数的含义, 以后会详细讲到.

下面就可以创建Message了,这里创建一个TextMessage。
  Message message = session.createTextMessage("Hello JMS!");

要想把刚才创建的消息发送出去,需要由Session和Destination创建一个消息生产者:
  MessageProducer producer = session.createProducer(queue);

下面就可以发送刚才创建的消息了:
  producer.send(message);

消息发送完成之后,我们需要创建一个消息消费者来接收这个消息:
  MessageConsumer comsumer = session.createConsumer(queue);
  Message recvMessage = comsumer.receive();

消息消费者接收到这个消息之后,就可以得到它的内容:
  System.out.println(((TextMessage)recvMessage).getText());

至此,一个简单的JMS例子就完成了。下面是全部源码 :

import javax.jms.Connection;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
public class MessageSendAndReceive {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); Connection connection = factory.createConnection();
connection.start(); Queue queue = new ActiveMQQueue("testQueue"); final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Message message = session.createTextMessage("Hello JMS!"); MessageProducer producer = session.createProducer(queue);
producer.send(message); System.out.println("Send Message Completed!"); MessageConsumer comsumer = session.createConsumer(queue);
Message recvMessage = comsumer.receive();
System.out.println(((TextMessage)recvMessage).getText());
}
}

深入掌握JMS(三):MessageListener

消息的消费者接收消息可以采用两种方式:

1、consumer.receive() 或 consumer.receive(int timeout);
  2、注册一个MessageListener。

采用第一种方式,消息的接收者会一直等待下去,直到有消息到达,或者超时。后一种方式会注册一个监听器,当有消息到达的时候,会回调它的onMessage()方法。下面举例说明:

 MessageConsumer comsumer = session.createConsumer(queue);
comsumer.setMessageListener(new MessageListener(){
@Override
public void onMessage(Message m) {
TextMessage textMsg = (TextMessage) m;
try {
System.out.println(textMsg.getText());
} catch (JMSException e) {
e.printStackTrace();
}
} });
 

深入掌握JMS(四):实战Queue

Queue实现的是点到点模型,在下面的例子中,启动2个消费者共同监听一个Queue,然后循环给这个Queue中发送多个消息,我们依然采用ActiveMQ。

import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue; public class QueueTest {
public static void main(String[] args) throws Exception {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); Connection connection = factory.createConnection();
connection.start(); //创建一个Queue
Queue queue = new ActiveMQQueue("testQueue");
//创建一个Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); //注册消费者1
MessageConsumer comsumer1 = session.createConsumer(queue);
comsumer1.setMessageListener(new MessageListener(){
public void onMessage(Message m) {
try {
System.out.println("Consumer1 get " + ((TextMessage)m).getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}); //注册消费者2
MessageConsumer comsumer2 = session.createConsumer(queue);
comsumer2.setMessageListener(new MessageListener(){
public void onMessage(Message m) {
try {
System.out.println("Consumer2 get " + ((TextMessage)m).getText());
} catch (JMSException e) {
e.printStackTrace();
}
} }); //创建一个生产者,然后发送多个消息。
MessageProducer producer = session.createProducer(queue);
for(int i=0; i<10; i++){
producer.send(session.createTextMessage("Message:" + i));
}
}
}

运行这个例子会得到下面的输出结果:

  1. Consumer1 get Message:0
  2. Consumer2 get Message:1
  3. Consumer1 get Message:2
  4. Consumer2 get Message:3
  5. Consumer1 get Message:4
  6. Consumer2 get Message:5
  7. Consumer1 get Message:6
  8. Consumer2 get Message:7
  9. Consumer1 get Message:8
  10. Consumer2 get Message:9

可以看出每个消息直被消费了一次,但是如果有多个消费者同时监听一个Queue的话,无法确定一个消息最终会被哪一个消费者消费。

深入掌握JMS(五):实战Topic

与Queue不同的是,Topic实现的是发布/订阅模型,在下面的例子中,启动2个消费者共同监听一个Topic,然后循环给这个Topic中发送多个消息。

import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQTopic; public class TopicTest {
public static void main(String[] args) throws Exception {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); Connection connection = factory.createConnection();
connection.start(); //创建一个Topic
Topic topic= new ActiveMQTopic("testTopic");
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); //注册消费者1
MessageConsumer comsumer1 = session.createConsumer(topic);
comsumer1.setMessageListener(new MessageListener(){
public void onMessage(Message m) {
try {
System.out.println("Consumer1 get " + ((TextMessage)m).getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}); //注册消费者2
MessageConsumer comsumer2 = session.createConsumer(topic);
comsumer2.setMessageListener(new MessageListener(){
public void onMessage(Message m) {
try {
System.out.println("Consumer2 get " + ((TextMessage)m).getText());
} catch (JMSException e) {
e.printStackTrace();
}
} }); //创建一个生产者,然后发送多个消息。
MessageProducer producer = session.createProducer(topic);
for(int i=0; i<10; i++){
producer.send(session.createTextMessage("Message:" + i));
}
}
}

运行后得到下面的输出结果:

  1. Consumer1 get Message:0
  2. Consumer2 get Message:0
  3. Consumer1 get Message:1
  4. Consumer2 get Message:1
  5. Consumer1 get Message:2
  6. Consumer2 get Message:2
  7. Consumer1 get Message:3
  8. Consumer2 get Message:3
  9. Consumer1 get Message:4
  10. Consumer2 get Message:4
  11. Consumer1 get Message:5
  12. Consumer2 get Message:5
  13. Consumer1 get Message:6
  14. Consumer2 get Message:6
  15. Consumer1 get Message:7
  16. Consumer2 get Message:7
  17. Consumer1 get Message:8
  18. Consumer2 get Message:8
  19. Consumer1 get Message:9
  20. Consumer2 get Message:9

说明每一个消息都会被所有的消费者消费。

深入掌握JMS(六):消息头

一个消息对象分为三部分:消息头(Headers),属性(Properties)和消息体(Payload)。对于StreamMessage和MapMessage,消息本身就有特定的结构,而对于TextMessage,ObjectMessage和BytesMessage是无结构的。一个消息可以包含一些重要的数据或者仅仅是一个事件的通知。

消息的Headers部分通常包含一些消息的描述信息,它们都是标准的描述信息。包含下面一些值:

  JMSDestination 
       消息的目的地,Topic或者是Queue。

  JMSDeliveryMode 
        消息的发送模式:persistent或nonpersistent。前者表示消息在被消费之前,如果JMS提供者DOWN了,重新启动后消息仍然存在。后者在这种情况下表示消息会被丢失。可以通过下面的方式设置:
       Producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);

JMSTimestamp 
       当调用send()方法的时候,JMSTimestamp会被自动设置为当前事件。可以通过下面方式得到这个值:
       long timestamp = message.getJMSTimestamp();

  JMSExpiration 
       表示一个消息的有效期。只有在这个有效期内,消息消费者才可以消费这个消息。默认值为0,表示消息永不过期。可以通过下面的方式设置:
       producer.setTimeToLive(3600000); //有效期1小时 (1000毫秒 * 60秒 * 60分)

  JMSPriority 
       消息的优先级。0-4为正常的优先级,5-9为高优先级。可以通过下面方式设置:
       producer.setPriority(9);

  JMSMessageID 
       一个字符串用来唯一标示一个消息。

  JMSReplyTo 
       有时消息生产者希望消费者回复一个消息,JMSReplyTo为一个Destination,表示需要回复的目的地。当然消费者可以不理会它。

  JMSCorrelationID 
       通常用来关联多个Message。例如需要回复一个消息,可以把JMSCorrelationID设置为所收到的消息的JMSMessageID。

  JMSType 
       表示消息体的结构,和JMS提供者有关。

  JMSRedelivered 
       如果这个值为true,表示消息是被重新发送了。因为有时消费者没有确认他已经收到消息或者JMS提供者不确定消费者是否已经收到。

除了Header,消息发送者可以添加一些属性(Properties)。这些属性可以是应用自定义的属性,JMS定义的属性和JMS提供者定义的属性。我们通常只适用自定义的属性。

后面会讲到这些Header和属性的用法。

深入掌握JMS(七):DeliveryMode例子

在下面的例子中,分别发送一个Persistent和nonpersistent的消息,然后关闭退出JMS。

import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
public class DeliveryModeSendTest {
public static void main(String[] args) throws Exception {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); Connection connection = factory.createConnection();
connection.start(); Queue queue = new ActiveMQQueue("testQueue");
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(queue);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
producer.send(session.createTextMessage("A persistent Message")); producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
producer.send(session.createTextMessage("A non persistent Message")); System.out.println("Send messages sucessfully!");
}
}

运行上面的程序,当输出“Send messages sucessfully!”时,说明两个消息都已经发送成功,然后我们结束它,来停止JMS Provider。

接下来我们重新启动JMS Provicer,然后添加一个消费者:

import javax.jms.Connection;
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;
import org.apache.activemq.command.ActiveMQQueue;
public class DeliveryModeReceiveTest {
public static void main(String[] args) throws Exception {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); Connection connection = factory.createConnection();
connection.start(); Queue queue = new ActiveMQQueue("testQueue");
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer comsumer = session.createConsumer(queue);
comsumer.setMessageListener(new MessageListener(){
public void onMessage(Message m) {
try {
System.out.println("Consumer get " + ((TextMessage)m).getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
});
}
}

运行上面的程序,可以得到下面的输出结果:

Consumer get A persistent Message

可以看出消息消费者只接收到一个消息,它是一个Persistent的消息。而刚才发送的non persistent消息已经丢失了。

另外, 如果发送一个non persistent消息, 而刚好这个时候没有消费者在监听, 这个消息也会丢失.

深入掌握JMS(八):JMSReplyTo

在下面的例子中,首先创建两个Queue,发送者给一个Queue发送,接收者接收到消息之后给另一个Queue回复一个Message,然后再创建一个消费者来接受所回复的消息。

import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
public class MessageSendReceiveAndReply {
public static void main(String[] args) throws Exception {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); Connection connection = factory.createConnection();
connection.start(); //消息发送到这个Queue
Queue queue = new ActiveMQQueue("testQueue");
//消息回复到这个Queue
Queue replyQueue = new ActiveMQQueue("replyQueue"); final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建一个消息,并设置它的JMSReplyTo为replyQueue。
Message message = session.createTextMessage("Andy");
message.setJMSReplyTo(replyQueue); MessageProducer producer = session.createProducer(queue);
producer.send(message); //消息的接收者
MessageConsumer comsumer = session.createConsumer(queue);
comsumer.setMessageListener(new MessageListener(){
public void onMessage(Message m) {
try {
//创建一个新的MessageProducer来发送一个回复消息。
MessageProducer producer = session.createProducer(m.getJMSReplyTo());
producer.send(session.createTextMessage("Hello " + ((TextMessage) m).getText()));
} catch (JMSException e1) {
e1.printStackTrace();
}
} }); //这个接收者用来接收回复的消息
MessageConsumer comsumer2 = session.createConsumer(replyQueue);
comsumer2.setMessageListener(new MessageListener(){
public void onMessage(Message m) {
try {
System.out.println(((TextMessage) m).getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
});
}
}

首先消息生产者发送一个消息,内容为“Andy”, 然后消费者收到这个消息之后根据消息的JMSReplyTo,回复一个消息,内容为“Hello Andy‘。 最后在回复的Queue上创建一个接收回复消息的消费者,它输出所回复的内容。

运行上面的程序,可以得到下面的输出结果:

  1. Hello Andy

原创的地址找不到,只找到转载的地址:http://blog.csdn.net/zhangxs_3/article/details/4034713

最新文章

  1. UML大战需求分析--阅读笔记3
  2. MVC5 网站开发实践 1、建立项目
  3. SQL2005中的事务与锁定(三)- 转载
  4. java jvm学习笔记十三(jvm基本结构)
  5. 爬虫:把廖雪峰的教程转换成 PDF 电子书
  6. wxPython中基本控件学习
  7. [置换群&amp;Polya计数]【学习笔记】
  8. unity UGUI实现类似NGUI切换Sprite的方式
  9. 17-Flink消费Kafka写入Mysql
  10. 字符串Contains匹配失效
  11. [agc016B][Colorful Hats]
  12. python web cgi
  13. javascript闭包和this对象
  14. 第五章 绘图基础(LINEDEMO)
  15. # 20155214 2016-2017-2 《Java程序设计》第8周学习总结
  16. &lt;转&gt;赋值表达式解析的流程
  17. sqlcmd导入大数据文件
  18. ardunio 实现RS485通讯-下位机
  19. struts2入门实例
  20. OpenERP 在context中写自己的部门ID

热门文章

  1. OC语言-01类和对象
  2. div+css知识点(2)
  3. Dining
  4. 【UVA10972】RevolC FaeLoN (求边双联通分量)
  5. Keil C中全局变量的使用
  6. 14.5.5.3 How to Minimize and Handle Deadlocks 如何减少和处理死锁
  7. 查看SGA和PGA使用率
  8. 【HDOJ】1501 Zipper
  9. iOS动态管理AutoLayout的约束NSLayoutConstraint
  10. hdoj 1010 Tempter of the Bone【dfs查找能否在规定步数时从起点到达终点】【奇偶剪枝】