JMS

转载:深入浅出JMS(一)——JMS简介

转载:JMS的例子

如果手机只能进行实时通话,没有留言和短信功能会怎么样?一个电话打过来,正好没有来得及接上,那么这个电话要传递的信息肯定就收不到了。为什么不能先将信息存下来,当用户需要查看信息的时候再去获得信息呢?伴随着这个疑惑,短息和留言应运而生,无论手机是否开机、是否未及时接到,我们都能得到其中的信息。JMS提供了类似这样的功能,本章我们将系统的学习JMS中的相关重要内容。

clip_image004

      Ø 掌握JMS基本概念及适用范围

      Ø 点对点模型与发布/订阅模型的区别和使用场合

      Ø 熟悉核心和通用的JMS API

      Ø 熟悉并理解JMS客户端开发的步骤

      Ø 消息的同步和异步接收的实现方式

      Ø 串包问题的解决办法

企业消息系统

      Java Message Service是由Sun开发的,它为 Java程序提供一种访问企业消息系统的方法。在讨论JMS之前,我们分来析一下企业消息系统。 
      企业消息系统,即面向消息的中间件(MOM),提供了以松散耦合的灵活方式集成应用程序的一种机制。它们提供了基于存储和转发的应用程序之间的异步数据发送,即应用程序彼此不直接通信,而是与作为中介的MOM 通信。MOM提供了有保证的消息发送,应用程序开发人员无需了解远程过程调用(PRC)和网络/通信协议的细节。ActiveMQ正是MOM中优秀的一员。

企业消息系统的好处

我们先来看看下图,应用程序A将Message发送到服务器上,然后应用程序B从服务器中接收A发来的消息,通过这个图我们一起来分析一下JMS的好处

image

图 1 JMS通讯示意图

提供消息灵活性

      应用程序A与应用程序B通过使用MOM的应用程序编程接口(API)发送消息进行通信。MOM 将消息路由给应用程序B,这样消息就可以存在于MOM中,MOM 负责处理网络通信。如果网络连接不可用,MOM会存储消息,直到连接变得可用时,再将消息转发给应用程序B。 
      灵活性的另一方面体现在,当应用程序A发送其消息时,应用程序B甚至可以不处于执行状态。MOM将保留这个消息,直到应用程序B开始执行并试着检索消息为止。这还防止了应用程序A因为等待应用程序B检索消息而出现阻塞。 
      这种异步通信要求应用程序的设计与现在大多数应用程序不同,不过对于时间无关或并行处理,它可能是一个极其有用的方法。

松散耦合

      企业消息系统的真正威力在于应用程序的松散耦合。在上面的图中,由应用程序A发送消息指定一个特定目标,如“订单处理”。而现在,是由应用程序B提供订单处理功能。 
      但是在将来,我们可以用不同的订单处理程序替换应用程序B,应用程序A将不再是明智之选。替换应用程序将继续发送消息完成“订单处理”,而消息也仍将得到处理。 
      同样,我们也可以替换应用程序A,只要替换应用程序继续发送消息进行“订单处理”,订单处理程序就无需知道是否有一个新的应用程序在发送订单。

JMS是什么

      JMS是一系列的接口及相关语义的集合,通过这些接口和和其中的方法,JMS客户端如何去访问消息系统,完成创建、发送、接收和读取企业消息系统中消息。 
      在JMS之前,每一家MOM厂商都用专有API为应用程序提供对其产品的访问,通常可用于许多种语言,其中包括Java语言。JMS通过MOM为Java程序提供了一个发送和接收消息的标准的、便利的方法。用JMS编写的程序可以在任何实现JMS标准的MOM上运行。 
      JMS可移植性的关键在于:JMS API是由Sun作为一组接口而提供的。提供了JMS功能的产品是通过提供一个实现这些接口的提供者来做到这一点的。开发人员可以通过定义一组消息和一组交换这些消息的应用程序,建立JMS应用程序,实现异步通讯。

JMS的目标

      JMS从提出以来,致力于完成如下几个目标: 
定义一组消息公用概念和实用工具。 
      
所有Java应用程序都可以使用JMS中定义的API去完成消息的创建、接收与发送,任何实现了JMS标准的MOM都可以作为消息的中介,完成消息的存储转发。 
最大化消息应用程序的可移植性。 
      
MOM提供了有保证的消息发送,应用程序开发人员无需了解远程过程调用(PRC)和网络/通信协议的细节,提供了程序的可移植性。 
最大化降低应用程序与应用系统之间的耦合度。 
      
由于MOM的存在,各个应用程序只关心和MOM之间如何进行消息的接收与发送,而无需关注MOM的另一边,其他程序是如何接收和发送的。

JMS两种消息模型

JMS提供了两种消息通信模型:

      Ø 点到点(P2P)模型

      Ø 发布/订阅(Pub/Sub)模型

clip_image010

图 2 JMS通讯模型

从图中可以看出,ClientA和ClientB是消息生产者,通过两种不同的目的地分别向ClientC、ClientD、ClientE和ClientF发送消息。 
      在ClientA、C、D之间的消息是点对点模型,使用这种模型,客户端发送消息到队列目的地(Queue),从这个队列里面只有一个消息接收者可以收到那个消息,其他访问同一目的地的接收者不会接收到该消息。如ClientC接收Queue中的Msg1消息,ClientD接收Queue中的Msg2消息。 
      在ClientB、E、F之间的消息是发布/订阅模型。使用这种广播模型,一个客户端发送消息给主题目的地(Topic),任何数量的消费订阅者可以从这个主题目的地来接收它们。如:ClientE和ClientF都接收这个Msg3这条消息。

点到点模型

点对点传递模型:生产者发送消息到一个特定的队列(Queue)中,而消费者从一个消息队列中得到消息,如下图所示:

image

图 3 点到点通讯模型示意图

点对点模型的特点:

Ø  每条消息有一个消费者

      每条只有一个消费者,如果一条消息被消息者接收,那么其他的消费者就不能得到这条消息了。

Ø 发送和接受消息与时间没有关系

      也就是说,生产者在发送消息后,消费者可以在任意的时刻接收,但有两个前提:

            1、消息未过期

            2、消息没有被其他的用户接收

      消费者也可以先运行,当生产者一运行,将消息发送到队列中,消费者即可从队列中获得消息,这叫“守株待兔“。

Ø  消费者必须确认对消息的接收

      收到消息后消费者必须确认消息已被接收,否则JMS服务提供者会认为该消息没有被接收,那么这条消息仍然可以被其他人接收。程序可以自动进行确认,不需要人工干预。

Ø  非持久的消息最多只发送一次

      非持久的消息最多只发送一次,表示消息有可能未被发送,造成未被发送的原因可能有:

            1、 JMS服务提供者出现宕机等情况,造成非持久信息的丢失

            2、 队列中的消息过期,未被接收

Ø  持久的消息严格发送一次

      我们可以将比较重要的消息设置为持久化的消息,持久化后的消息不会因为JMS服务提供者的故障或者其他原因造成消息丢失。

发布/订阅模型

      发布/订阅模型:发布/订阅传递消息类型与主题(Topic)有关。生产者发布消息,而消费者订阅感兴趣的消息,生产者将消息和一个特定的主题(Topic)连在一起,消息传递系统(MOM)根据消费者注册的兴趣,将消息传递给消费者。这种类型非常类似出版报纸、杂志的形式,如下图所示:

image

图 4 发布/订阅通讯模型示意图

发布/订阅模型的特点:

Ø  每个消息都可以有多个(0,1,……)订阅者

      每条消息可以有多个消费者,如果报纸和杂志一样,谁订阅了谁都可以获得。

Ø  订阅者只能消费他们订阅之后出版的消息

      这就要求订阅者必须先订阅,生产者再发布。即订阅者必须先运行,再等待生产者的运行,这和点对点类型有所差异。

Ø  订阅者必须保持为活动状态才能使用这些消息

      即订阅者必须保持活动状态等待发布者发布的消息,如果订阅者在发布者发布消息之后才运行,则不能获得先前发布者发布的消息。




1、JMS是一个由AS提供的Message服务。它能接受消息产生者(Message Provider)所发出的消息,并把消息转发给消息消费者(Message  Consumer)。
2、JMS提供2种类型的消息服务:(1)Queue,即点对点,每个消息只转发给一个消息消费者使用。(2)Topic,即发布和订阅,每个消息可以转发给所有的订阅者(消费者)。
3、WEBLOGIC 8下的JMS配置:
(1)配置JMS Connection Factory
(2)配置JMS File Store(目前所找到的文档都是配置File Store,其实在具体的应用中,可能JMS JDBC Store更广泛,但暂时没有找到资料)
(3)配置JMS Server
(4)在JMS Server的destinations中配置JMS Queue或者JMS Topic
其中提供给消息产生者和消息消费者使用的是JMS Connection Factory的JNDI和JMS Queue或者JMS Topic的JNDI。
4、消息产生者向JMS发送消息的步骤:
(1)使用JNDI查询对象JMS ConnectionFactory和Destination(JMS Queue/Topic)
(2)使用管理对象JMS ConnectionFactory建立连接Connection
(3)使用连接Connection 建立会话Session
(4)使用会话Session和管理对象Destination创建消息生产者MessageSender
(5)使用消息生产者MessageSender发送消息
一个消息发送者的例子:

[java]  view plain copy
  1. package myjms;  
  2. import java.util.*;  
  3. import javax.naming.*;  
  4. import javax.jms.*;  
  5. public class MessageProducter {  
  6.   public static void main(String[] args) {  
  7.     String queueConnectionFactoryName = "myjmsconnectionfactory"//JMS Connection Factory的JNDI  
  8.     String queueName = "myjmsqueue"//JMS Queue或者JMS Topic的JNDI  
  9.     boolean transacted = false;//transaction模式  
  10.     int acknowledgementMode = Session.AUTO_ACKNOWLEDGE;//acknowledgement模式  
  11.     String message="Message need to send";//模拟需要发送的消息  
  12.     Properties properties = new Properties();  
  13.     properties.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");  
  14.     properties.put(Context.PROVIDER_URL, "t3://localhost:7001");  
  15.     try {  
  16.       Context context = new InitialContext(properties);  
  17.       Object obj = context.lookup(queueConnectionFactoryName);  
  18.       QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory) obj;//JMS Connection Factory的获得  
  19.        
  20.       obj = context.lookup(queueName);  
  21.       Queue queue = (Queue) obj;//JMS Queue或者JMS Topic的获得  
  22.       QueueConnection queueConnection=queueConnectionFactory.createQueueConnection();//产生连接  
  23.       queueConnection.start();  
  24.       QueueSession queueSession = queueConnection.createQueueSession(transacted, acknowledgementMode);  
  25.       TextMessage textMessage = queueSession.createTextMessage();  
  26.       textMessage.clearBody();  
  27.       textMessage.setText(message);  
  28.       QueueSender queueSender = queueSession.createSender(queue);  
  29.       queueSender.send(textMessage);  
  30.       if (transacted) {  
  31.         queueSession.commit();  
  32.       }  
  33.       if (queueSender != null) {  
  34.         queueSender.close();  
  35.       }  
  36.       if (queueSession != null) {  
  37.         queueSession.close();  
  38.       }  
  39.       if (queueConnection != null) {  
  40.         queueConnection.close();  
  41.       }  
  42.     }  
  43.     catch(Exception ex){  
  44.       ex.printStackTrace();  
  45.     }  
  46.   }  
  47. }  

5、消息消费者从JMS接受消息的步骤:
(1)使用JNDI查询对象JMS ConnectionFactory和Destination(JMS Queue/Topic)
(2)使用管理对象JMS ConnectionFactory建立连接Connection
(3)使用连接Connection 建立会话Session
(4)使用会话Session和管理对象Destination创建消息消费者MessageReceiver
(5)使用消息消费者MessageReceiver接受消息,需要用setMessageListener将MessageListener接口绑定到MessageReceiver
消息消费者必须实现了MessageListener接口,需要定义onMessage事件方法。
一个消息消费者的例子:

[java]  view plain copy
  1. package myjms;  
  2. import java.util.*;  
  3. import javax.naming.*;  
  4. import javax.jms.*;  
  5. public class MessageReciever  
  6.     implements MessageListener {  
  7.   public void onMessage(Message message) {  
  8.     if (message instanceof TextMessage) {  
  9.       TextMessage textMessage = (TextMessage) message;  
  10.       try {  
  11.         System.out.println("Message content is:" + textMessage.getText());  
  12.       }  
  13.       catch (JMSException e) {  
  14.         e.printStackTrace();  
  15.       }  
  16.     }  
  17.   }  
  18.   public static void main(String[] args) {  
  19.      
  20.     MessageReciever msgRcvr=new MessageReciever();  
  21.     String queueConnectionFactoryName = "myjmsconnectionfactory";  
  22.     String queueName = "myjmsqueue";  
  23.     boolean transacted = false;  
  24.     int acknowledgementMode = Session.AUTO_ACKNOWLEDGE;  
  25.     Properties properties = new Properties();  
  26.     properties.put(Context.INITIAL_CONTEXT_FACTORY,  
  27.                    "weblogic.jndi.WLInitialContextFactory");  
  28.     properties.put(Context.PROVIDER_URL, "t3://localhost:7001");  
  29.     try {  
  30.       Context context = new InitialContext(properties);  
  31.       Object obj = context.lookup(queueConnectionFactoryName);  
  32.       QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory)  
  33.           obj;  
  34.       obj = context.lookup(queueName);  
  35.       Queue queue = (Queue) obj;  
  36.       QueueConnection queueConnection = queueConnectionFactory.  
  37.           createQueueConnection();  
  38.       queueConnection.start();  
  39.       QueueSession queueSession = queueConnection.createQueueSession(transacted,  
  40.           acknowledgementMode);  
  41.       QueueReceiver queueReceiver = queueSession.createReceiver(queue);  
  42.       queueReceiver.setMessageListener(msgRcvr);  
  43.       synchronized(msgRcvr){  
  44.         msgRcvr.wait(100000);  
  45.       }  
  46.       if (queueReceiver != null) {  
  47.         queueReceiver.close();  
  48.       }  
  49.       if (queueSession != null) {  
  50.         queueSession.close();  
  51.       }  
  52.       if (queueConnection != null) {  
  53.         queueConnection.close();  
  54.       }  
  55.     }  
  56.     catch (Exception ex) {  
  57.       ex.printStackTrace();  
  58.     }  
  59.   }  
  60. }  

6、Message-driven Bean
MDB实际上就是一个消息消费者的客户端程序。它由AS EJB Container来管理。在JBUILDER生成一个MDB非常简单。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值