帝国软件
  设为首页 加入收藏 关于我们
 
解密帝国网站管理系统
栏 目:
 
您的位置:首页 > 技术文档 > JAVA编程
J2EE 组件开发:消息驱动的EJB
作者:佚名 发布时间:2005-04-02 来源:不详
 
  一、概述

  消息服务是一种在分布
合、语言中立、平台中立的
之间传递的消息进行封装,
务为消息的客户程序提供了
户程序能够通过一个友好的
式应用之间提供消息传递服务的
特点,而且通常是可配置的。它
并在分布式消息客户程序结合的
一个接口,这个接口隔离了底层
编程接口方便地通信。
软件,具有可靠、异步、宽松结
的实现原理是:对发送者和接收者
位置加上一个软件处理层。消息服
的消息服务, 使得各种不同的客


  Java消息服务(Java M
序如何以一种标准化的形式
务提供者通过该接口向客户
Point-to-Point)和发布-
essage Service,JMS)是一个J
与底层的消息服务提供者交互。
程序提供JMS消息服务。JMS提供
订阅消息模式(Publish-Subscr
ava API,它定义了消息的客户程
JMS提供了一种接口,底层消息服
了点对点消息模式(
ibe)。点对点消息模式通过一
  个消息队列实现,消息的生产者向队列写入消息,消息的消费者从队列提取消息。      

  发布-订阅消息模式通
这个层次结构发布消息,消
过一个话题(Topic)节点构成
息的消费者向这个结构订阅消息
的层次结构实现,消息的生产者向

  点对点消息模式具有如下特点:                                                 
  每一个消息只有一个消费者。                                                   
  消息的接收者和发送者之间不存在时
否在运行,接收者都可以提取信息。
间上的依赖关系。不论发送者发送消息时接收者是

  接收者对于成功处理的消息给出回执。                                           

  发布-订阅消息模式具有如下特点:                                             
  每一个消息可以有多个消费者。                                                 
  向某个话题订阅的客户程序只能收到
订阅者必须保持活动状态。因此,发布者
定程度上放宽了对这种依赖关系的要求,
有了持久性订阅,当订阅者不活动时发送
那些在它订阅之后发布的消息。为了接收到消息,
和订阅者之间存在时间上的依赖关系。JMS API在一
允许创建持久性订阅(Durable S ubscription)。
的消息也能接收到。
                                                                               
  EJB 2.0规范定义了一
MDB),它能够以EJB的形式
接口使得EJB能够异步地接
的构造方式与普通JMS消息
消息的消费者是一个EJB。
户程序不通过接口访 问Bea

种新的EJB类型,即消息驱动的E
实现JMS消息的接收者。消息驱
收和处理JMS消息生产者发送到
生产者的构造方式完全一样,也
相对于会话Bean和实体Bean而言
n。与会话Bean和实体Bean不同

JB(Message-Driven EJB,简称
动的EJB实现一组新的接口,这组
队列或话题的消息。EJB客户程序
就是说,JMS消息生产者不必知道
,消息驱动的Bean最大的特点是客
,消息驱动的Bean只有一个Bean类


  从某些方面看,消息驱动的Bean类似于无状态会话Bean:                   
  消息驱动的Bean不为特定的客户保留数据或对话状态。                         
  一个消息驱动Bean的所有的实例都是
驱动Bean的实例。容器能够建立消息驱动
的Bean能够处理来自多个客户程序的消息
等价的,这使得容器能够把消息指派给任意一个消息
Bean的缓冲池,实现消息的并发处理。一个消息驱动

  消息驱动Bean的实例变
开的数据库连接,或者是对
onMessage()方法处理消息
型之一,然后按照应用的业
量可以在处理客户消息期间包含
EJB对象的引用。当一个消息到
。onMessage()方法通常把消息
务逻辑的要求处理消息。
一些状态信息,例如JMS连接、打
达,容器调用消息驱动Bean的
定型(cast)成为五种JMS消息类


  传递给消息驱动Bean的
作都属于该事务的一部分。
该使用消息驱动的Bean呢?
能异步接收。一些时候,为
阻塞,这时,我们可以用消
消息可能处于一个事务之内,这
如果消息处理结果被回退,则系
会话Bean和实体Bean能够发送JM
防止过多地占用服务器资源,在
息驱动的Bean异步接收消息。
时,onMessage()方法内的所有操
统将再次投递该消息。哪些时候应
S消息,能够同步接收消息,但不
服务器端的组件中,我们想要避免

                                                                               
  二、MDB体系结构

  图一描述了消息驱动的Bean组件的基本体系结构。                             
  在图一中,位于顶端的
EnterpriseBean接口派生出
是javax.ejb.EnterpriseBean接
了javax.ejb.MessageDrivenBea
口,它是所有EJB的基础接口。
n接口,所有消息驱动的EJB类
  必须实现javax.ejb.MessageDrivenB
javax.jms.MessageListener接口。公用
显示的MyMessageDrivenEJBean,必须同
口。消息驱动的EJB与其他类型的EJB不同
是遵从EJB容器的接口要求。由于这个原
ean接口。此外,消息驱动的Bean必须实现
的、非最终的、非抽象的消息驱动的EJB,比如图一
时实现MessageListener接口和MessageDrivenBean接
,它们不把业务方法导出给客户程序,它们关心的只
因,消息驱动的Bean必须有一个不需要参
  数的公用构造方法(ejbCreate()方
法),而且不应该实现finalize()方法。
                                                                               
  2.1 MDB接口                                                           
  在消息驱动的Bean中,
ageDrivenContext的对象实
个方法。
setMessageDrivenContext()方
例传递给EJB,它是MessageDriv

法用来把一个Mess
enBean接口定义中容器调用的第一

  MessageDrivenContext
EJB实例访问容器提供的运
对象封装了一个EJB消息驱动容
行时消息驱动上下文
器上下文的接口,支持消息驱动的

  对于消息驱动的EJB来说,关键之一
器准备创建消息驱动EJB的实例时,它将
,可能是因为它要构造一个Bean实例的缓
ejbCreate()方法和其他Bean上的EJB构造
始化方法。
是要实现一个没有参数的ejbCreate()方法。当EJB容
调用这个方法。容器之所以决定创建某个EJB的实例
冲池,也可能是因为它接收到了客户的请求。这个
方法类似,属于EJB实现的一种特殊的构造函数或初

  当EJB容器准备不让Bea
ejbRemove()方法。何时在
EJB客户程序的任何约束。
操作时,容器会调用ejbRem
n实例继续处理客户程序的请求
消息驱动的Bean上调用ejbRemov
应当注意的是,容器并不保证一
ove()方法;但是,当消息驱动
时,它就会调用消息驱动Bean的
e()方法由EJB容器单独决定,不受
定调用ejbRemove()方法 .在正常
的Bean向容器抛出了
  系统异常时,不能保证
按时检查和清除Bean分配的
ejbRemove()方法一定会被调用
所有资源。
。由于这个原因,Bean开发者必须

  对于Bean开发者来说,最重要的任务
由Bean实例处理时,容器将调用onMessag
javax.jms.Message的实例,消息驱动的E
消息处理。
也许是实现onMessage()方法。当一个异步消息必须
e()方法。onMessage()方法的参数是一个普通的JMS
JB实例从这个Message的实例提取待处理的数据完成

                                                                               
  2.2 JMS消息接口                                                       
  那么,在onMessage()
提取哪些信息呢?图二描述
息系统中,Message接口是
Root Interface)。Destin
传递模式,所以图二还显示
方法调用传入的 JMS消息中,消
了基本JMS消息类型的核心接口
在系统中传递的所有消息的最基
ation接口描述了消息传递的一
了Message接口与DeliveryMode
息驱动的Bean如何提取信息,可以
和概念。在一个以JMS为基础的消
本的接口(或称之为根接口,
个终端;类似地,由于消息有一个
接口的概念上的关系。
  JMS消息的头信息可以通过一组标准
getJMSXXX()或setJMSXXX()形式(下面我
头信息中的属性名字,例如getJMSDelive
set方法操作的标准头信息属性包括:唯
,消息传递模式,消息类型,以及消息的
的方法设置或提取,这组标准方法的名字为
们分别称之为get方法和set方法),其中XXX是消息
ryMode()方法。在Message接口中,通过get方法和
一的消息ID,时标(Timestamp),答复和目标地址
优先级。

  在JMS消息中,JMS容器
setXXXProperty()方法设置
operty(java.lang.String
。名字以JMSX前缀开头的属
消息头相对而言)的五种类
据由BytesMessage封装,Se
封装,键-值对由MapMessag
提供者特有的属性可以通过getX
,其中XXX表示属性的类型,例
name)。每一个属性有一个通过S
性作为标准JMS属性保留。与消
型对应,五种消息类型扩展了Me
rializable对象由ObjectMessag
e封装,I
XXProperty()方法提取,或通过
如byte getBytePr
tring对象指定的名字和相应的值
息正文数据(或称之为消息体,与
ssage接口,如图三所示。Byte数
e封装,String消息由TextMessage

  /O流由StreamMessage封装。                                     

  这些派生消息类型上的
础接口内,有一个通用的cl
。clearBody()方法只清除
消息后,消息正文的状态将
方法为特定类型的消息正文定义
earBody()方法,这个方法清除
消息正文,不清除消息头或属性
和新消息的空白正文状态一样。
了get和set操作,而在Message基
消息的正文,并把它置入只写模式
。如果消息正文是只读的,调用该


  2.3 MDB客户程序接口                                                   
  消息驱动Bean的客户程序并不知道接
动Bean的客户程序的构造方法与普通JMS
四所示。从图中我们可以看出,JMS Conn
称和目录接口(Java Naming and Direct
收端实际处理消息的将是一个EJB。事实上,消息驱
客户程序的构造方法完全一样。JMS的核心体系如图
ectionFactory(连接工厂)初始上下文通过Java名
ory Interface,JND
  I)创建。随后,连接
可以获得创建消息生产者和
序就是消息的生产者,它发
工厂将用来创建与JMS服务提供
消息消费者的会话(Session)
送的消息将由消息驱动的Bean(
者的连接。有了JMS连接,我们就
。实际上,消息驱动Bean的客户程
即消息消费者)接收。

  三、点对点消息队列模式

  图五显示了在一个支持点对点消息队
上是核心JMS体系的一个扩展,特别地,
会话、消息生产者、消息消费者等都用点
利用JNDI获得一个QueueConnectionFacto
列的系统中JMS的基本体系结构。消息队列体系实际
它加入了对消息队列功能的支持。连接工厂、连接、
对点消息队列形式的接口进行了扩展。JMS客户程序
ry对象的引用。随后,我们用Que
  ueConnectionFactory.createQueueC
的实例。调用createQueueConnection()
可以使用该方法不带参数的版本,此时假
Connection接口的一种子类型,它代表着
调用createQueueSession()方法创建Queu
一个boolean类型的参数指定了QueueSess
在createQueueSession()调用中通过参数
AUTO_ACKNOWLEDGE,CLIENT_ACKNOWLED
onnection()方法之一创建一个QueueConnection对象
方法时可以指定一个用户名字和密码,或者,我们也
定使用默认用户身份。QueueConnection接口是
一个与JMS点对点消息队列服务的连接。JMS客户程序
eSession的实例,createQueueSession()方法调用中
ion对象是否要提供事务支持。另外,回执的模式也
指定,这个参数的值可以是三个静态的标识符之一:

  GE,DUPS_OK_ACKNOWLE
,调用Queue.getQueueName
DGE。QueueSession.createQueu
()方法可以返回队列的名字。
e()方法返回一个Queue对象的实例


  QueueSession.createS
可以把消息发送到Queue。
这些不同的send()方法能够
send()方法调用中指定的Qu
ender()方法创建一个QueueSend
消息可以通过各种不同的QueueS
把消息发送给QueueSender对象
eue对象。消息递送模式、优先
er消息生产者,利用QueueSender
ender.send()方法发送到Queue,
关联的Queue对象,或者发送给
级、消息的有效时间都
  可以在调用QueueSender.send()方法
义的各种消息构造方法创建。
时指定。发送给Queue的消息可以用Session接口中定


  四、发布-订阅消息模式

  图六显示了在一个支持发布-订阅消
机制也是核心JMS机制的一种扩展,增加
连接、会话、消息生产者、消息消费者等
通过JNDI获得一个TopicConnectionFacto
息模式的系统中JMS的基本体系结构。发布-订阅消息
了一些适合发布-订阅消息模式的功能。连接工厂、
都用发布-订阅形式的接口进行了扩展。JMS客户程序
ry对象的引用。TopicConnection
  Factory.createTopicC
createTopicConnection()
法不带参数的版本,此时假
onnection()方法用来创建Topic
方法时可以指定一个用户名字和
定使用默认用户身份。
Connection对象的实例。调用
密码,或者,我们也可以使用该方

  TopicConnection接口
息服务的连接。JMS客户程
是Connection接口的一种子类型
序调TopicConnection.createTo
,它代表着一个与JMS发布-订阅消
picSession()方法创建Top
  icSession的实例。会
话的事务支持和回执模式也在创
建TopicSession时指定。

  TopicSession.createT
题目的地,发布者向该目的
不同的方式实现话题名称的
形式的描述。
opic()方法返回一个Topic对象
地发送消息,订阅者从该目的地
层次结构,调用Topic.getTopic

的实例。Topic接口封装了一个话
接收消息。不同的服务提供者按照
Name()方法可以获得话题的String

  TopicSession.createP
息发布到Topic。消息可以
不同的publish()方法能够
publish()方法调用中指定
调用TopicPublisher.publi
的各种消息构造方法创建。
ublisher()方法创建一个TopicP
通过各种不同TopicPublisher.p
把消息发送给TopicPublisher对
的Topic对象。消息递送模式、
sh()方法时指定。发送给Topic

ublisher消息生产者,它用来把消
ublish()方法发布到Topic,这些
象关联的Topic对象,或者发送给
优先级、消息的有效时间都可以在
的消息可以用Session接口中定义


  五、实例

  本示例应用是一个消息驱动Bean应用的简单例子,由以下两部分构成:           
  SimpleMessageClient:J2EE应用客
户程序,向队列发送消息。
  SimpleMessageEJB:一
息。
个消息驱动的Bean,异步地接收

和处理由客户程序发送到队列的消

  图七描述了这个应用的
j2eeadmin命令创建。JMS提
Bean的实例处理消息。
结构。客户端应用把消息发送到
供者(这里是J2EE服务器)把消

队列,队列由管理员通过
息传递给消息驱动Bean的实例,由

  该示例应用的完整代码可以从本文最后下载。                                     

  5.1 客户端                                                               
  SimpleMessageClient把消息发送到S
impleMessageBean监听的队列。客户程序首先确定
  连接工厂和队列:                                                             
  queueConnectionFacto
ry = (QueueConnectionFactory
) jndiContext.lookup
  ("java:comp/env/jms/MyQueueConne
ctionFactory");
  queue = (Queue) jndi
Context.lookup("java:comp/en
v/jms/QueueName");
  接下来,客户程序创建队列连接、会话和一个消息发送器:                         
  queueConnection = qu
eueConnectionFactory.createQ
ueueConnection();
  queueSession = queueConnection.c
reateQueueSession(false,
  Session.AUTO_ACKNOWLEDGE);                         

  queueSender = queueS
ession.createSender(queue);
  最后,客户程序把几个消息发送到队列:                                         
  message = queueSession.createTex
tMessage();
  for (int i = 0; i < NUM_MSGS;
i++) {
  message.setText("我是" + msgArray[i] );   

  System.out.println("
Sending message: " +
  message.getText());                                       
  queueSender.send(message);                         
  }                                                                           

  5.2 MDB组件                                                           
  SimpleMessageEJB类阐明了编写消息驱动Bean类的要求:       
  实现MessageDrivenBean接口和Messa
geListener接口。
  类定义为public类型。                                                   
  类不能定义成abstract或final。                                   
  实现一个onMessage()方法。                                         
  实现一个ejbCreate()方法和一个ejbRemove()方法。         
  包含一个public类型的不需要参数的构造方法。                             
  不能定义finalize()方法。                                           
  与会话Bean和实体Bean不同,消息驱
先定位消息驱动的Bean,再调用这些Bean
们可以包含由onMessasge()方法内部调用
用消息驱动Bean的onMessage()方法。在S
的消息定型(cast)成为TextMessage类
动的Bean不定义客户程序访问的接口。客户程序不是
上的方法。虽然消息驱动的Bean没有业务方法,但它
的辅助方法。当队列接收到一个消息,EJB容器将调
impleMessageBean类中,onMessage()方法把接收到
型,然后显示出文本信息:
  public void onMessage(Message in
Message) {
  TextMessage msg = null;                               
  try {                                                                   
  if (inMessage instanceof TextMes
sage) {
  msg = (TextMessage) inMessage;                 
  System.out.println("MESSAGE BEAN
:收到消息: "
  + msg.getText());                                           
  } else {                                                             
  System.out.println("消息类型错误: "                   
  + inMessage.getClass().getName());         
  }                                                                           
  } catch (JMSException e) {                         
  e.printStackTrace();                                     
  mdc.setRollbackOnly();                                 
  } catch (Throwable te) {                             
  te.printStackTrace();                                   
  }                                                                           
  }                                                                           

  消息驱动Bean的ejbCre
ate()方法和ejbRemove()方法必
须符合以下要求:
  访问控制修饰符必须是
throws子句不能定义任何应
ejbCreate()方法和ejbRemo
public。返回值类型必须是void
用自定义的异常。不能带有参数
ve()方法都是空的,不执行任何
。不能有static和final修饰符。
。在SimpleMessageBean类中,
有实际意义的操作。

  5.3 打包                                                                 
  接下来我们要把上面的应用打包成一
Jar文件。通常,打包过程可以通过工具
用模块部署描述器中,顶级元素下面包含
,每一个元素描述一个消息驱动Bean的配
下所示。元素内定义了消息驱动Bean的配
、配置参数、安全信息、事务信息、消息
个J2EE EAR文件。首先要把SimpleMessageEJB打包成
完成,但理解模块部署描述器仍是必要的。在EJB应
元素。下面可以包含一组元素(按照EJB2.0新规范)
置和部署。SimpleMessageEJB的ejb-jar.xml文件如
置和部署信息,例如唯一的Bean名字、Bean类的名字

  目的地类型等。                                                               
  ......                                                                 

  SimpleMessageJAR                                             


  SimpleMessageEJB                                             
  SimpleMessageEJB                                             
  SimpleMessageBean                                           
  Container                                                           

  javax.jms.Queue                                               

  SimpleMessageEJB                                             
  Bean                                                                     
  onMessage                                                           

  javax.jms.Message                                           
  Required                                                             

  除了ejb-jar.xml部署描述器之外,

通常还要有面向特定平台和环境的部署描述器。大多

  数时候,这种描述器可以用GUI工具编写。请参见下载代码中提供的例子。         
  打包好各个模块之后,接着还要把J2
EE应用打包成EAR文件。有关这一步骤的详细说明,
  请参见开发平台的相关文档。本文以
后有关部署和运行的说明,就以打包后的EAR文件为
  基础。                                                                       

  5.4 部署和运行                                                           
  假设我们在Sun的J2EE
输出,我们必须以-verbose
参考实现上部署和测试这个示例
模式启动服务器:
应用。为便于查看消息驱动Bean的

  j2ee -verbose用下面的j2eeadmin命令创建队列:           
  j2eeadmin -addJmsDestination jms
/MyQueue queue
  验证队列已经创建成功:j2eeadmin
-listJmsDestination
  启动deploytool,选择菜单“File-->Open”,打开SimpleMessageApp.ear文件。接着选择菜单“Tools --> Deploy”,部署应用。出现部署提示时,选中“Return ClientJAR”检查框。在一个命令窗口中,进入EAR文件(SimpleMessageAppClient.jar文件)所在目录,把环

  境变量APPCPATH设置为
SimpleMessageAppClient.jar。
然后,执行下面的命令:
  runclient -client SimpleMessageA
pp.ear -name SimpleMessageClient -textauth

  在登录提示中,输入用
户名字j2ee,输入密码j2ee。此
时,客户程序将输出以下内容:

  Sending message: 我是老大孙悟空                             
  Sending message: 我是老二猪八戒                             
  Sending message: 我是老三沙和尚                             
  在启动j2ee服务器的命令窗口,我们可以看到如下输出:         
  
评论】【加入收藏夹】【 】【打印】【关闭
※ 相关链接
 ·Sun在开放源代码J2EE认证上又迈出  (2005-04-02)
 ·J2EE 1.4 application Server fo  (2005-04-02)
 ·《J2EE核心模式》(DAO模式)  (2005-04-02)
 ·J2EE 和 .NET之间的对比  (2005-04-02)
 ·J2EE初学者需要理解的问题  (2005-04-02)
 ·J2EE和XML为企业应用软件创造机会  (2005-04-02)
 ·J2EE相关设计模式讨论  (2005-04-02)
 ·J2EE1.4新特性之Servlet2.4新特性  (2005-04-02)
 ·J2EE1.4新特性之JDBC3.0的新特性  (2005-04-02)
 ·J2EE运行环境性能优化艺术之二  (2005-04-02)

   栏目导行
  PHP编程
  ASP编程
  ASP.NET编程
  JAVA编程
   站点最新
·致合作伙伴的欢迎信
·媒体报道
·帝国软件合作伙伴计划协议
·DiscuzX2.5会员整合通行证发布
·帝国CMS 7.0版本功能建议收集
·帝国网站管理系统2012年授权购买说
·PHPWind8.7会员整合通行证发布
·[官方插件]帝国CMS-访问统计插件
·[官方插件]帝国CMS-sitemap插件
·[官方插件]帝国CMS内容页评论AJAX分
   类别最新
·谈谈JDBC
·JDBC专题介绍
·JDBC接口技术
·利用weblogic的POOL(连接池)连接
·Jsp中调用Oracle存储过程的小例子
·JSP数据库操作例程
·JSP数据库连接大全
·用连接池提高Servlet访问数据库的效
·一种简单JDBC连接池的实现
·数据库连接池Java实现小结
 
关于帝国 | 广告服务 | 联系我们 | 程序开发 | 网站地图 | 留言板 帝国网站管理系统