Enterprise JavaBeans Distilled
作者: Tnk Luo
第九次:
消息驱动Bean(续)
使用哪个消息模型?
这两种模型背后的基本原理在JMS规范中。JMS是用于访问现存消息系统,而提供公共API的方式出现的。在现如今的概念阶段,一些消息厂商提供了点对点模型支持,而另一些提供对发布-订阅模型支持。所以,JMS需要提供支持两种模型的API才能赢得业界的广泛支持。JMS 1.0.2规范部要求JMS供应者支持两种模型。然而,EJB 2.0厂商需要提供对两种消息模型的支持。
几乎任何事情都可用pub/sub模型完成,或用点对点完成。反之亦然。以此类推,类似于开发者的编程语言选择。理论上,能够用Pascal写的应用也可以用C完成。用C++能完成的任何事情,也能用Java做。在某些情形下,都有一定的选择,或者取决于对那种模型的熟悉程度罢了。
在大部分情况下,模型的选择取决于模型各自不同的优点。对于发布-订阅而言,任何数目的订阅者都能监听某个topic,并都能够收到相同消息的拷贝。比如,考虑发布者广播了股票报价这样一种情况。如果任何特定的订阅者当前没有连接,并错过了很好的报价,发布者不会去关注。相比之下,点对点Session很可能倾向于另一端特定应用的一对一对话。在这种情形下,每条消息都值要紧。
另外,消息所代表数据信息的范围和多样性也是一个因素。使用pub/sub时,消息是基于特定topic提供的过滤功能来分发到消费者的。即使当消息是用于和某个已知的应用建立一对一对话,使用多个topic的pub/sub来隔离不同类型的消息也是pub/sub的优势所在。每种消息类型能单独通过各自的消费者和onMessage()监听器来处理。
当仅仅想让特定接收者处理一次给定消息时,点对点更加方便。这也许是这两种模型最关键的区别:p2p保证仅仅有一个消费者处理每条消息。当消息需要依次单独处理时,这一点尤为重要。
实体和会话Bean不该接收消息
JmsClient_1用于消费TravelAgent EJB生产的消息。那么,其他的实体,或会话Bean也能接收哪些消息吗?答案是肯定的,但那可不是好办法。
实体和会话Bean会对来自EJB客户的Java RMI调用作出响应,但不能编写为,类似消息驱动Bean一样,对JMS消息的响应。这意味着,不可能写消息驱动的会话,或实体Bean。EJB的这种对JMS消息响应的局限性,使得消息驱动Bean为什么会在EJB 2.0中引入的原因。消息驱动Bean被设计成消费来自topic或queue的消息。消息驱动Bean补充了以前EJB中的不足,我们将在下一节给出如何编写它们的例子。
开发实体或会话Bean来消费来自业务方法的JMS消息时可能的,但是这个方法必须首先被EJB客户调用。比如,调用Hypothetical EJB中的业务方法,其中设置了JMS session并试着查看来自queue的消息:
public class HypotheticalBean implements javax.ejb.SessionBean {
InitialContext jndiContext;
public String businessMethod() {
try{
QueueConnectionFactory factory = (QueueConnectionFactory)
jndiContext.lookup("java:comp/env/jms/QueueFactory");
Queue topic = (Queue)
jndiContext.lookup("java:comp/env/jms/Queue");
QueueConnection connect = factory.createQueueConneciton();
QueueSession session = connect.createQueueSession(true,0);
QueueReceiver receiver = session.createReceiver(queue);
TextMessage textMsg = (TextMessage)receiver.receive();
connect.close();
return textMsg.getText();
} catch(Exception e) {
throws new EJBException(e);
}
}
...
}
消息消费者,QueueReceiver,用于取得queue中的消息。尽管程序设计正确,但这是很危险的操作,因为对QueueReceiver.receive()的调用将诸塞当前线程,直到消息可用为止。如果消息不会发送到接收者的queue中,该线程将一直被诸塞。换句话说,如果没有消息发送到这个queue中,QueueReceiver将一直等待下去。
当然也有一些择中的办法,使得receive()方法变得更安全。比如,receive(long timeout)给出了等待时间,一旦超过了这个时间,如果消息还没到达,QueueReceiver将停止诸塞当前线程,并放弃该消息。同时,也有receiveNoWait()方法,它会检查消息,如果没有等待,则返回null,因此避免了线程诸塞。
尽管这些receive()方法更安全,但仍然是危险的操作。不能够保证receive()方法预期运行、或者程序员的失误(比如,使用了错误的receive()方法),等等这些所带来的风险都是很大的。另外,消息驱动Bean提供了强有力、简单的企业Bean ,并专门为消费JMS消息而设计的。本书建议不要试着在实体,或会话Bean 中消费消息。
JMS更多内容
JMS(包括一般意义上的企业消息),代表了分布式计算中一种强有力的典范。用本人的观点理解,Java消息服务和EJB自身同等重要,在使用JMS开发之前一定要理解它。
尽管本章给出了JMS的总体概述,但只是给出足够的材料为下一节讨论消息驱动Bean打下基础。JMS具有很多的特性和细节,以至于本书不可能包含内容广泛的JMS。为理解JMS以及如何使用它,需要读者独立研究它。JMS的详细材料,《Java消息服务》,Richard Monson-Haefel和David Chappell(O’Reilly)。花时间学习JMS是很值得的。
待续。。。。。。。。
(作者其它文章:http://www.csdn.net/develop/author/netauthor/worldheart/ )
谢谢!!