UML软件工程组织

消息驱动组件分析
作者:苏洋 本文选自:赛迪网 2003年01月06日

 


基于EJB1.0或1.1规范开发的应用系统对于来自J2EE应用系统内部EJB组件对象或者应用系统外部事件消息的响应方法是通过创建独立的外部程序来作为事件监听器接收事件消息,在对接收的事件消息内容进行分析和处理后,调用其它会话或实体类型EJB组件中的商务方法。这种应用系统对事件消息的响应方式过于笨拙,使得系统的整体性能受到限制。为此,EJB2.0规范定义了一种能够响应事件消息的组件——消息驱动组件(Message-Driven Entreprise JavaBean)。

EJB系列讲座
第一讲:分布式多层体系结构
第二讲:EJB基本结构解析
第三讲:EJB会话组件分析
第四讲:如何定义无状态会话类型EJB组件
第五讲:创建有状态会话类型EJB组件
第六讲:EJB的实体组件
第七讲:组件管理持久性EJB组件详解
第八讲:容器管理持久性EJB组件



EJB2.0规范中定义的消息驱动组件是一种部署在EJB容器中、由Java事件消息激活的无状态类型EJB组件。消息驱动组件对象实例以异步的方式接收来自Java消息服务(Java Message Service,JMS)队列中的事件消息。当组件对事件消息进行分析后,根据消息中携带的事件内容对事件消息进行响应。消息驱动组件作为基于J2EE规范的应用系统中的事件监听器(Listener),可以对来自常规Java客户端应用、EJB组件对象实例、部署在WEB容器中的JSP组件甚至J2EE应用系统外部的应用程序发出的符合Java消息服务规范的事件消息进行响应。消息驱动组件在J2EE中的应用方式如下图所示:



图1 J2EE应用系统中消息驱动组件对事件的响应方式


消息驱动组件的创建规则


与会话和实体类型组件不同,定义消息驱动组件不需要定义该组件的Home或Remote接口对象,只需定义组件类即可创建消息驱动组件对象。与无状态会话类型EJB组件类似,该类型组件不能维护客户端在EJB服务器中的状态并且EJB容器中的组件对象实例具有相对短暂的生命期。EJB容器同样能够象处理实体类型EJB组件那样将处于实例池中的消息驱动类型EJB组件对象实例转换为关闭状态,以提高EJB服务器的性能、减少EJB组件对服务器端资源的消耗。

通常,创建消息驱动组件应遵循如下规则:

◇EJB组件类实现javax.ejb.MessageDrivenBean接口和javax.jms.MessageListener接口,并且该类必须定义为非抽象(abstract)、非最终(final)的公共(public)类型;

◇在组件类中定义public类型的构造函数;

◇在组件类中定义名称为ejbCreate的EJB容器创建组件对象实例的方法,在该方法中可以申请组件需要的系统资源;

◇在组件类中定义名称为ejbRemove的方法用于释放消息驱动组件对象实例占用的系统资源;

◇在组件类中定义名称为onMessage的方法来响应事件消息,因此可以认为该方法是消息驱动组件的商务方法;

◇在组件类中定义名称为setMessageDrivenContext的方法,使得消息驱动组件能够获取组件运行的环境信息。

创建消息驱动类型组件对象


定义组件类

按照前面关于消息驱动组件的定义规则,创建一个用于客户端动态更新EJB服务器股票名称和价格的消息驱动类型EJB组件对象。根据组件实现的商务功能,将该组件对象命名为"StockPrice",相应地,该EJB组件类命名为"StockPriceBean"。该组件类的定义框架如下面代码所示:

public class StockPriceBean implements 
MessageDrivenBean, MessageListener{
		private transient MessageDrivenContext ctx = null;
    	private Context context;
        public StockPriceBean (){}
    public void setMessageDrivenContext(MessageDrivenContext ctx)
{ this.ctx = ctx; }
… …
}


在组件类的定义框架中,包括一个构造函数和用于保存消息驱动类型EJB组件环境上下文的setMessageDrivenContext方法。

定义组件生命期方法

按照EJB2.0规范,消息驱动组件类中需要定义用于EJB容器创建组件对象实例的ejbCreate方法和删除组件对象实例的ejbRemove方法。两个方法的定义规则如下:

◇方法必须定义为public类型;

◇方法的返回值类型必须为缺省(void)类型;

◇方法不能定义为静态(static)类型或者最终(final)类型;

◇方法抛出的异常类型不能为用户定义异常类型,只能是RemoteException类型和CreateException类型;

◇两个方法不能定义任何输入参数。

与会话类型EJB组件类似,ejbCreate方法由EJB容器在启动过程中自动调用、ejbRemove方法由客户端调用remove方法时由EJB容器调用,因而不需要在方法中定义任何实现代码。两个方法的定义如下:

public void ejbCreate() {}
public void ejbRemove() {}


定义消息驱动组件的商务方法

消息驱动组件中的商务方法是用于对事件消息进行响应的onMessage方法。该方法的定义规则如下:

◇该方法必须定义为public类型,其返回值类型为缺省(void)类型;

◇方法不能定义为静态(static)类型或者最终(final)类型;

◇该方法需要定义消息(Message)类型的方法输入参数,以封装客户端应用发送的事件消息内容。

消息驱动组件的客户端可以发送文本消息(TextMessage)、对象消息(ObjectMessage)、名-值对消息(MapMessage)、字节消息(BytesMessage)和流消息(StreamMessage)五种类型的事件消息。在向StockPriceBean消息驱动组件发送事件消息的客户端应用的实现代码中,利用消息对象实例的setText方法封装了文本类型的事件内容,因此,组件商务方法的实现代码首先判断Message参数是否为文本格式的事件消息。如果消息类型符合判断条件,则利用该实例对象的getText方法将消息中封装的字符串参数解析出来。onMessage方法的实现代码如下:

public void onMessage(Message inMessage) {
        TextMessage msg = null;
        try {
            if (inMessage instanceof TextMessage) {
                String strMessage = (TextMessage) inMessage.getText());
	System.out.println("Received stock Message : "+strMessage);
            } else {
                System.out.println("Message type error");
            }
        }catch(JMSException e){
      }catch(Throwable te){
}
    }


创建消息驱动EJB组件的客户端应用


消息驱动组件的客户端应用是指能够发送符合Java消息服务(JMS)规范事件消息的独立客户端应用、J2EE应用系统中部署在WEB层中的WEB组件或者同一EJB容器中其它类型的EJB组件。消息驱动组件的客户端应用向EJB组件部署过程中配置的EJB服务器消息队列发送事件消息,消息驱动组件监听来自该队列的消息。客户端应用可以通过如下步骤向EJB服务器中的消息队列发送事件消息:

创建队列连接厂对象和队列对象

在消息驱动组件部署过程中,已经配置了消息驱动组件监听的消息队列。客户端应用需要利用JNDI方式在JNDI上下文(JndiContext)对象中定位队列连接厂(QueueConnectionFactory)对象和事件消息队列(Queue)对象:

QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory)
jndiContext.lookup("java:comp/env/jms/EventQueueConnectionFactory");
Queue queue = (Queue)jndiContext.lookup("java:comp/env/jms/EventQueue");


在上面的代码中,在创建JNDI上下文对象后,利用该对象的lookup方法获取部署过程中指定的名称为EventQueueConnectionFactory的队列连接厂对象实例和名称为EventQueue的消息队列对象实例。

创建队列连接对象

获取队列连接厂对象后,利用该对象的createQueueConnection方法创建队列连接(QueueConnection)对象,从而建立客户端应用与消息驱动组件的事件联系:

QueueConnection queueConnection =
queueConnectionFactory.createQueueConnection();


创建队列会话对象和事件消息发送对象

当客户端建立与消息驱动组件的事件联系后,客户端应用需要通过创建队列会话对象(QueueSession)在客户端与事件消息队列之间维持会话过程,在此基础上创建消息发送对象(QueueSender)来发送事件消息。为此,在客户端应用的实现代码中利用队列连接对象的createQueueSession方法创建队列会话对象、利用队列会话对象的createSender方法创建队列消息发送对象,见下面的代码:

QueueSession queueSession = queueConnection.createQueueSession(
false,Session.AUTO_ACKNOWLEDGE);
QueueSender queueSender = queueSession.createSender(queue);


创建消息对象、封装消息内容并发送事件消息

在客户端应用中创建队列会话对象和队列消息发送对象后,可以通过消息(Message)对象实例来创建符合JMS规范的事件消息并利用队列消息发送对象将创建的事件消息发送到消息驱动组件监听的消息队列中,见下面的代码:

Message message = queueSession.createTextMessage();
message.setText("The Stock Name : Founder" + "The Stock Price : 10.85");
System.out.println("Sending Message: " +message.getText());
queueSender.send(message);


在上面的代码中,利用队列会话对象的createTextMessage方法创建文本格式的事件消息并利用setText方法设置该消息对象中封装的消息内容。然后,利用队列消息发送对象的send方法将创建的文本格式事件消息发送到EJB服务器端消息驱动组件监听的消息队列中,实现EJB组件以及整个J2EE应用对外部事件的响应。

上面客户端应用实现代码中涉及的各个对象均封装在JMS包中,感兴趣的读者可以查阅相关资料来了解这些对象的含义以及对象中封装的方法。



版权所有:UML软件工程组织