Enterprise JavaBeans Distilled
作者: Tnk Luo
第八次:
消息驱动Bean(续)
JMS是异步的
JMS消息的一个主要优势在于它是异步的。换句话说,JMS客户能发送消息,而无需等待回复。我们来比较一下它和Java RMI同步发送消息的灵活性。RMI是一种用于组装事务组件的极好选择,但在使用上很受限。每次客户调用EJB的方法时,都会因等待方法执行结果而诸塞当前线程。这种“lock-step”处理使得客户依赖于EJB服务器的可用性,从而导致了客户和EJB的紧耦合。
在JMS中,客户异步发送消息到目的地(topic或queue),同时其他的JMS客户也能从该目的地地址接收消息。当JMS客户发送消息时,它不用等待回复。因为消息发送到路由器,路由器负责将消息分发给其他的JMS客户。发送消息的客户和接收消息的客户形成了松耦合,因为发送者不再依赖于接受者的可用性。
RMI的这种限制使得JMS成为了,用于和其他应用通讯,极为诱人的替代品。使用标准的JNDI ENC,EJB能获得到JMS供应者的JMS连接,并用连接分发异步消息给其他的应用。比如,TravelAgent会话Bean可以使用JMS来通知其他的应用程序,预定已经处理过了,如图13-1所示。
图 13-1. 使用JMS的TravelAgent EJB
在这种情形下,接收来自TravelAgent EJB的JMS消息的应用可能是消息驱动Bean,或者是企业中的其他应用,或者是其他组织中的应用,这些组织因为被告知预定已经完成而受益。还可能是,一起分享信息的商业合作者,或者是添加客户到目录邮件列表的内部市场应用程序。
JMS使得EJB发送消息而没有出现诸塞。EJB不知道消息接收者,因为它将消息发送到虚拟通道(目的地),而不是直接给另外的应用。应用能够选择从哪个虚拟通道接收消息,并接受新预定的通知。
企业消息有趣的一方面是,这种技术本身的松耦合、异步特定意味着:发送者的事务和安全context并没有对消息的接收者形成影响。比如,当TravelAgent EJB发送票务消息时,JMS供应者可能要鉴定它,但它的安全context并没有给接收该消息的JMS客户形成影响。当JMS客户接收到来自TravelAgentEJB的消息时,它对消息发送的安全context并没有概念。其实事实就是这样,因为发送者和接收者在使用不同安全管理的操作环境中。
类似地,事务也从不在发送者和接收者之间有关系。首先,发送者对接收者没有概念。如果消息发送到存在一个,或成千上万个接收者的topic中,在这种模糊的环境中管理这种分布式事务不太现实。另外,接收消息的客户可能在消息发送后很长时间内都没有收到它,因为它们临时down机了,或者不能够接收到消息。JMS强有力的关键点在于它允许发送者和接收者是临时的松耦合。事务一般都是快速执行的,因为事物锁定资源,具有不可预期的长时间事务的可能性也太不现实。
A JMS client can, however, have a distributed transaction with the JMS provider so that it manages the send or receive operation in the context of a transaction. For example, if the TravelAgent EJB's transaction fails for any reason, the JMS provider will discard the ticket message sent by the TravelAgent EJB. Transactions and JMS are covered in more detail in Chapter 14.
然而,JMS客户能够和JMS供应者有分布式事务,从而能够在同一事物上下文中管理发送和接收操作。比如,如果TravelAgent EJB事务由于某种原因失败,JMS供应者将丢弃TravelAgent EJB发送的票务消息。本书第14章有事务和JMS的详细阐述。
JMS消息模型:发布-订阅 和 点对点
JMS提供了两种消息模型:发布-订阅和 点对点。JMS规范称之为,messaging domains。在JMS术语中,发布-订阅 和 点对点经常分别缩写为pub/sub和p2p(或PTP).本章这两种叫法都有。
简而言之,发布-订阅用于一对多广播式消息,然而点对点用于一对一分发消息(如图13-2所示)。
图 13-2. JMS messaging domains
发布-订阅
在发布-订阅消息中,生产者能通过称之为topic的虚拟通道将消息发送给多个消费者。消费者可以选择订阅的topic。任何发送到topic的消息会将分发到所有订阅了它的消费者。每个消费者会接收到每条消息的一份拷贝。发布-订阅模型大体上是一个基于推技术的模型,因为消息会自动广播到消费者,而不需消费者向它们发送请求或为新消息pull topic。
在发布-订阅模型中,发送消息的生产者不依赖于接收消息的消费者。比如,使用发布-订阅的JMS客户能够建立持久的订阅,其间允许消费者断开、以后连接,并收集消费者断开期间发布的消息。
本章的TravelAgent EJB使用发布-订阅编程模型,并使用Topic对象作为目的地。
点对点
点对点消息模型允许JMS客户借助于,称之为queue的虚拟通道来同步和异步,发送和接收消息。其中点对点消息模型,一般都是基于pull(或者poll)的模型,消息需要客户向queue发送请求,而不是自动推到客户端。(JMS规范没有明确给出必须如何实现发布-订阅和点对点模型。这两者都可以使用推技术或拉技术,但从概念上讲发布-订阅是推和点对点是拉。)
queue可能有多个接收者,但只有一个接收者会接收到每条消息。正如图13-2所示,JMS供应者会关注消费消息的JMS客户,确保每条消息仅仅被一个JMS客户消费掉。JMS规范没有给出在多个接收者之间分发消息的规则。
用于点对点的消息API类似于发布-订阅中的。下面给出的代码演示了,如何修改TravelAgent EJB使得它使用基于queue的点对点API,而不是前述例子中使用的基于topic的发布-订阅模型。
public TicketDO bookPassage(CreditCardDO card, double price)
throws IncompleteConversationalState {
...
TicketDO ticket = new TicketDO(customer,cruise,cabin,price);
String ticketDescription = ticket.toString();
QueueConnectionFactory factory = (QueueConnectionFactory)
jndiContext.lookup("java:comp/env/jms/QueueFactory");
Queue queue = (Queue)
jndiContext.lookup("java:comp/env/jms/TicketQueue");
QueueConnection connect = factory.createQueueConneciton();
QueueSession session = connect.createQueueSession(true,0);
QueueSender sender = session.createSender(queue);
TextMessage textMsg = session.createTextMessage();
textMsg.setText(ticketDescription);
sender.send(textMsg);
connect.close();
return ticket;
} catch(Exception e) {
throw new EJBException(e);
}
}
待续。。。。。。。。
(作者其它文章:http://www.csdn.net/develop/author/netauthor/worldheart/ )
谢谢!!