【IT168 技术文章】
EJB 2.0 消息驱动 bean
在使用 J2EE 1.3 和 EJB 2.0 时,消息驱动 bean(MDB)只能起到相当有限的作用。它们让应用程序异步地接收传递 JMS 目标的消息。而 MDB 需要实现 javax.jms.MessageListener,如清单 1 所示:
清单 1. javax.jms.MessageListener 接口
2 void onMessage(Message message);
3 }
MDB 还需要实现 MessageDrivenBean 接口。结果,典型的类看起来可能类似清单 2 中的 ExampleMdb :
清单 2. 示例 EJB 2.0 MDB
2 public void ejbCreate() throws CreateException { ... }
3 public void ejbRemove() { ... }
4 public void setMessageDrivenContext(MessageDrivenContext ctx) { ... }
5 public void onMessage(Message message) {
6 if (msg instanceof TextMessage) {
7 String text = ((TextMessage) message).getText();
8 InitialContext context = new InitialContext();
9 ExampleHome home = (ExampleHome)context.lookup("java:comp/env/ejb/Example");
10 Example bean = home.create();
11 bean.operation(text);
12 }
13 }
14 }
如果像清单 2 那样遵照 EJB 2.0 规范的建议,那么 onMessage 方法负责对消息的内容进行解包,然后调用其他 EJB 执行实际的业务逻辑。
但是别误会 —— EJB 2.0 MDB 当然有它们的好处。对于初学者来说,因为 MDB 不是由客户机调用的,所以不需要编写 home、remote 或 local 接口。而且 —— 最主要的一个好处就是,多个实例可以并行操作。在没有 MDB 时,应用程序可能已经确定了一个异步接收消息的目标,但是由于没有将工作复制到另外一个线程中的能力,所以应用程序须先处理第一个消息才能处理下一个消息。
就像其他 EJB 那样,MDB 能够使用 bean 托管事务或者容器托管事务。后者对 MDB 有一些扭曲。首先,只允许使用两个事务属性:Required 和 NotSupported。这是完全合理的。因为没有客户机调用 MDB,没有需要继承的事务,所以要做的就是能够指出 bean 是否应当在事务中运行。第二,也是更重要的,如果指定了事务属性 Required,那么传递到 MDB 的消息就作为消息的一部分接收。如果有什么事情出错,事务将回滚,那么消息将被重新放在目标上,再次进行处理。
正如在清单 3 中可以看到的,MDB 只用于 JMS 的这个事实也反映在部署描述符中:
清单 3. EJB 2.0 部署描述符
2 <enterprise-beans>
3 <message-driven>
4 <ejb-name>Example MDB</ejb-name>
5 <ejb-class>example.ExampleMDB</ejb-class>
6 <transaction-type>Bean</transaction-type>
7 <acknowledge-mode>Auto-acknowledge</acknowledge-mode>
8 <message-driven-destination>
9 <destination-type>javax.jms.Topic</destination-type>
10 <subscription-durability>Durable</subscription-durability>
11 </message-driven-destination>
12 <message-selector>
13 JMSType = 'car' AND color = 'red'
14 </message-selector>
15 </message-driven>
16 </enterprise-beans>
17 </ejb-jar>
18
在清单 3 中可以看到,部署描述符中的一些元素对应着 JMS 概念中的应答模式、订阅、持久性和消息选择器。另外一个元素给出了消息目标的类型,它必须是 javax.jms.Queue 或者是 javax.jms.Topic。