基于消息Bean的EJB异步通信
Bromon原创 请尊重版权
异步通信是一个提升程序执行效率的很重要的手段,而性能问题又是EJB诞生以来一直都很受关注的话题。EJB执行效率不高的原因是客户端需要查询和调用远程接口,而本身在处理数据是很快的,毕竟EJB有比较完善的缓冲机制,几十万的app server也不是白吃内存的。客户端程序如果能够采用异步通信,只负责以消息的形式发送请求和需要处理的数据,不用等待系统查询、调用远程接口,可以节省大量时间,这也是EJB 2.0中引入消息驱动Bean的一个重要原因。J2EE的消息机制允许你以消息的形式传递对象,我们可以利用它实现很多应用。
在最近正在写的一个考试系统中,系统把学生对每一个题目的回答都实时记录到数据库,这样做会有比较频繁的数据库操作,对性能有比较大的影响,但是可以让学生的每一次答题都得到永久性保存,避免因为意外死机或异常退出造成学生提交的答案丢失。毫无疑问,数据的安全可靠是第一位的,但是上百个学生并发操作,这个负载也是很巨大的。为了在稳定和性能上谋求平衡,我们考虑这样一种模型:
◆在服务器端建立一个永久性的队列,该队列可以保证数据安全,即使服务器意外重启,里面的对象也不丢失。并且有一种机制保证队列中的对象只会被处理一次。
◆客户端把答案数据封装成javabean,然后提交到这个队列中,提交之后不必等待数据处理完成,直接进行以后的操作,产生新的数据后继续往队列里存放,不必去关心数据什么时候会被处理。
◆服务器以FIFO的顺序处理队列中的数据包。
结构大致如下图:
?
很明显,这里只提供一种单向通信,但是并非被迫,完全可以在建立另外一个队列,存放返回的消息,对应的消息通过消息ID进行关联。以消息bean为核心的java消息服务(JMS)实际上就是这样一个框架。
首先设计一个操作答案数据表的类:
?
它包含增加答案的方法和修改已有答案的方法,在实际的项目中,它由一个映射数据表的CMP Entity Bean和一个封装程序逻辑的SessionBean构成,是一个典型的session facade模式。实际的系统大致是这样:
在一个系统中同时使用CMP和Hibernate来做映射,是一个非常怪异的设计,这样做只是为了使系统更有研究和讨论的价值,实际应用中恐怕我自己也要仔细考虑是否采用BMP代替Hibernate。
编写消息bean之前,首先定义消息中要传递的是什么对象:
?
下面是消息Bean的代码:
/*
?* 消息bean,处理针对Answer的操作
?* Created on 2004-7-27
?*/
package org.bromon.examer.message;
import javax.ejb.MessageDrivenBean;
import javax.jms.*;
import org.bromon.examer.base.*;
import org.bromon.examer.session.*;
public class AnswerMessageBean implements MessageDrivenBean, MessageListener
{
?private javax.ejb.MessageDrivenContext messageContext = null;
?//定义上下文
?public void setMessageDrivenContext(
??javax.ejb.MessageDrivenContext messageContext)
??throws javax.ejb.EJBException
?{
??this.messageContext = messageContext;
?}
?public void ejbRemove()
?{
??messageContext = null;
?}
?//收到消息后将执行这个方法
?public void onMessage(javax.jms.Message message)
?{
??try
??{
???if(message instanceof ObjectMessage)
???{
????AnswerOperate ap=(AnswerOperate)((ObjectMessage)message).getObject();
????//调用EJB对AnswerOperate对象进行处理
???}
????System.out.printn("消息处理完毕");
??}catch(Exception e)
??{
???System.out.println(e);
??}
?}
}
消息如何保障安全呢?有两个手段,一是使用消息验证,客户必须提供匹配的帐号密码才能访问消息中的数据。二是对消息中的对象加密,客户必须持有对应的密钥才能获得对象。