Java消息服务JMS详解

开发 后端
本文向您介绍Java中的消息服务JMS,Java消息服务提供了点对点模式和发布-订阅模式,文中将详细介绍这两种服务。

Java消息服务(JMS Java Message Services)提供了点对点模式(Point-to-Point Queue)和发布-订阅模式(Publish-Subscribe Topics).

Queue仅允许一个消息传送给一个客户(一对一):

Java消息服务JMS的接收者和发送者之间不存在时间上的依赖关系。不论发送者发送消息时接收者是否在运行,接收者都可以提取信息。接收者对于成功处理的消息给出回执。

Topics可以有多个客户端(一对多,多对多):

向某个话题订阅的客户程序只能收到那些在它订阅之后发布的消息。为了接收到消息,订阅者必须保持活动状态。因此,发布者和订阅者之间存在时间上的依赖关系。

点对点消息模式通过一个消息队列(Queue)实现,消息的生产者向队列写入消息,消息的订阅者从队列提取消息。发布-订阅消息模式通过一个话题(Topic)节点构成的层次结构实现,消息的生产者向这个层次结构发布消息,消息的订阅者向这个结构订阅消息。

消息驱动的Bean只有一个Bean类。从某些方面看,JMS消息驱动的Bean类似于无状态会话Bean:消息驱动的Bean不为特定的客户保留数据或对话状态。

  1. @MessageDriven(activationConfig={  
  2.    @ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Queue"),  
  3.    @ActivationConfigProperty(propertyName="destination",propertyValue="queue/jms")  
  4. }) 

@MessageDriven注释指明这是一个消息驱动Bean,并使用@ActivationConfigProperty注释配置消息的各种属性,其 中destinationType属性指定消息的类型,消息有两种类型topics 和queues,下面是这两种消息类型的介绍:

Topics 可以有多个客户端。用topic发布允许一对多,或多对多通讯通道。消息的产生者被叫做publisher, Java消息服务接受者叫做subscriber。destinationType属性对应值:javax.jms.Topic

Queue 仅仅允许一个消息传送给一个客户。一个发送者将消息放入消息队列,接受者从队列中抽取并得到消息,消息就会在队列中消失。第一个接受者抽取并得到消息后,其他人就不能再得到它。destinationType属性对应值:javax.jms.Queue destination属性用作指定消息路径,消息驱动Bean在发布时,如果路径不存在,容器会自动创建该路径,当容器关闭时该路径会自动被删除

当一个消息到达queue/jms队列时,就会触发onMessage方法,消息作为一个参数传入.

  1. package com.julycn.jms;  
  2.  
  3. import javax.ejb.ActivationConfigProperty;  
  4. import javax.ejb.MessageDriven;  
  5. import javax.jms.JMSException;  
  6. import javax.jms.Message;  
  7. import javax.jms.MessageListener;  
  8. import javax.jms.TextMessage;  
  9.  
  10. @MessageDriven(activationConfig = {  
  11.         @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),  
  12.         @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/jms") })  
  13. public class MessageQueue implements MessageListener {  
  14.  
  15.     public MessageQueue() {  
  16.  
  17.     }  
  18.  
  19.     public void onMessage(Message message) {  
  20.         TextMessage tmsg = (TextMessage) message;  
  21.         try {  
  22.             System.out.println(tmsg.getText());  
  23.         } catch (JMSException e) {  
  24.             e.printStackTrace();  
  25.         }  
  26.     }  
  27.  
  1. package com.julycn.client;  
  2.  
  3. import javax.jms.JMSException;  
  4. import javax.jms.Queue;  
  5. import javax.jms.QueueConnection;  
  6. import javax.jms.QueueConnectionFactory;  
  7. import javax.jms.QueueSender;  
  8. import javax.jms.QueueSession;  
  9. import javax.jms.TextMessage;  
  10. import javax.naming.InitialContext;  
  11. import javax.naming.NamingException;  
  12.  
  13. public class MessageQueueClient {  
  14.  
  15.     public static void main(String[] args) {  
  16.         QueueConnection conn;  
  17.         QueueSession session;  
  18.         Queue queue;  
  19.         QueueSender sender;  
  20.         TextMessage msg;  
  21.  
  22.         try {  
  23.             InitialContext ctx = new InitialContext();  
  24.             QueueConnectionFactory qcf = (QueueConnectionFactory) ctx  
  25.                     .lookup("ConnectionFactory");  
  26.             conn = qcf.createQueueConnection();  
  27.             session = conn.createQueueSession(false,  
  28.                     QueueSession.AUTO_ACKNOWLEDGE);  
  29.             queue = (Queue) ctx.lookup("queue/jms");  
  30.             msg = session.createTextMessage("你好,好久不见!");  
  31.             sender = session.createSender(queue);  
  32.             sender.send(msg);  
  33.             sender.close();  
  34.         } catch (NamingException e) {  
  35.             e.printStackTrace();  
  36.         } catch (JMSException e) {  
  37.             e.printStackTrace();  
  38.         }  
  39.  
  40.     }  
  41.  

(1) 得到一个JNDI初始化上下文(Context);

例子对应代码:

Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.provider.url", "localhost:1099");
props.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming");
InitialContext ctx = new InitialContext(props);

注意:可以写在代码中,也可以写在jndi.properties文件中.

(2) 根据上下文来查找一个连接工厂TopicConnectFactory/ QueueConnectionFactory (有两种连接工厂,根据是topic/queue来使用相应的类型);

例子对应代码:

QueueConnectionFactory qcf =(QueueConnectionFactory) ctx.lookup("ConnectionFactory");

(3) 从连接工厂得到一个连接(Connect 有两种[TopicConnection/ QueueConnection]);

例子对应代码:conn = qcf.createQueueConnection();

(4) 通过连接来建立一个会话(Session);

例子对应代码:session= conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);

这句代码意思是:建立不需要事务的并且能自动接收Java消息服务收条的会话,在非事务Session 中,JMS消息传递的方式有三种:
Session.AUTO_ACKNOWLEDGE :当客户机调用的receive方法成功返回,或当MessageListenser 成功处理了消息,session将会自动接收消息的收条。

Session.CLIENT_ACKNOWLEDGE :客户机通过调用消息的acknowledge方法来接收消息。接收发生在session层。接收到一个被消费的消息时,将自动接收该session已经 消费的所有消息。例如:如果消息的消费者消费了10条消息,然后接收15 个被传递的消息,则前面的10 个消息的收据都会在这15 个消息中被接收。

Session.DUPS_ACKNOWLEDGE :指示session缓慢接收消息。

(5) 查找目的地(Topic/ Queue);

例子对应代码:queue =(Queue) ctx.lookup("queue/jms");

(6) 根据会话以及目的地来建立消息制造者(TopicPublisher/QueueSender)和消费者(TopicSubscriber/QueueReceiver).
例子对应代码:

         msg = session.createTextMessage("你好,好久不见!");
         sender = session.createSender(queue);
         sender.send(msg);

备注:如果运行时出现javax.naming.NameNotFoundException: jms not bound , 是因为JBoss不会自已建立一个Queue对象,因此,需要手工来配置Queue对象。可以<JBoss5.x安装目录>\server\default\deploy目录中建立一个xxx-service.xml文件,其中xxx可以任意取值,但必须跟“-service”后缀,例如,abc-service.xml。该文件可以放在deploy或其子目录(可以是多层子目录)中。该文件的内容如下:

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <server> 
  3.     <mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=jms"> 
  4.         <depends optional-attribute-name="DestinationManager"> 
  5.             jboss.mq:service=DestinationManager</depends> 
  6.     </mbean> 
  7. </server> 

<mbean>元素的name属性值中的name必须是jms,要与queue/jms中的/后面的部分一致.

 

【编辑推荐】

  1. 成为Java高手需要注意的25个学习目标
  2. Java理论和实践: 理解JTS
  3. Java内存模型详解
  4. Java与.NET的WebServices相互调用
  5. 用纯Java代码调用JavaFX的功能
责任编辑:佚名 来源: JavaEye
相关推荐

2009-06-17 16:56:46

Spring JMS

2009-06-17 16:39:03

Spring JMS

2020-11-05 10:40:18

ActiveMQ

2009-06-12 17:45:16

JMS集群JBoss集群

2017-02-28 08:57:41

JavaJMS队列

2018-03-29 08:38:10

2009-11-23 20:29:20

ibmdwWeb

2013-01-05 09:58:35

JavaEEJavaEE7JMS 2.0

2009-04-13 11:37:12

IBMdWSOAP

2010-04-13 17:00:43

Unix消息队列

2012-05-25 15:35:43

JMSJava

2009-06-16 13:25:02

JBoss和JMS

2022-06-02 08:21:07

RocketMQ消息中间件

2024-07-11 11:17:00

消息队列Java

2011-08-18 10:59:57

iPhone开发消息通信NSNotificat

2022-08-09 08:31:29

RocketMQ消息中间件

2023-05-08 08:09:26

路由元信息谓词

2019-02-19 15:20:12

消息总线架构异步

2010-07-17 01:20:00

Telnet服务

2022-10-08 07:31:26

微服务编排体系
点赞
收藏

51CTO技术栈公众号