消息驱动EJB
消息驱动Bean就是一个标准的JMS消息异步消费者
通过使用MDB规范,开发者只需要实现一个onMessage(Message msg)方法,甚至无须获取JMS Session,也无须理会MDB何时启动——EJB容器会自动启动MDB来监听消息目的,开发者只要通过Annotation来指定JMS消息目的、消息目的的类型即可。
为了区分无状态Session Bean和MDB的适用场景,只要把握他们的区别即可:无状态的Session Bean提供了业务接口,客户端需要用同步方式来调用无状态Session Bean。MDB则不允许客户端直接调用,只是一个消息监听者。
下面是消息驱动EJB的Bean类的基本要求
1)MDB的Bean实现类必须直接(通过类声明)或间接(通过Annotation或部署描述文件)来实现消息监听器接口MessageListener
2)MDB类只能是一个使用public修饰的POJO,不能是其他MDB类的子类
3)MDB类必须包含无参数的构造器。如果程序员没有为MDB类提供构造器,系统将会为之提供无参数的构造器
4)由于EJB容器会操作MDB类,因此不要使用final或abstract修饰MDB的Bean实现类
5)MDB类中不应该定义finalize方法。如需要回收资源,应该利用@PreDestroy修饰的方法来回收。
使用@MessageDriven时可以指定一个messageListener属性,该属性指定MDB Bean实现类锁实现的接口,从而可以让MDB的Bean实现类间接地实现MessageListener接口。
@MessageDriven可以指定如下属性
1)mappedName:指定MDB正在监听的消息主题或消息队列的JNDI名称。
2)name:指定MDB的标识名
3)messageListener:指定MDB Bean类所实现的接口
4)activationConfig:可接受一组@ActivationConfigProperty作为参数,每个@ActivationConfigProperty配置一组key-value对,用于为MDB配置额外的属性,可以指定几个常用的属性如下
1)acknowledgeMode:指定JMS消息的确认方式
2)destinationType:指定MDB所监听消息目的的类型,可以是javax.jms.Topic或javax.jms.Queue两个值的其中之一,分别代表消息主题和消息队列。
3)destination:指定MDB所监听的消息目的的JNDI绑定名
@MessageDriven(activationConfig = {// @ActivationConfigProperty(// propertyName = "destinationType", propertyValue = "javax.jms.Queue"),// @ActivationConfigProperty(// propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),// @ActivationConfigProperty(// propertyName = "destination", propertyValue = "MessageQueue") }, // messageListenerInterface = javax.jms.MessageListener.class, // mappedName = "MessageQueue") public class SimpleMDB { public void onMessage(Message msg) { try { if (msg instanceof TextMessage) { TextMessage txt = (TextMessage) msg; String content = txt.getText(); System.out.println("the message is " + content); } } catch (JMSException e) { e.printStackTrace(); } } }
在实际中MDB获取了JMS消息之后,可以调用容器中其他Session Bean来处理该消息——只要通过依赖注入将Session Bean注入到该MDB中即可。
也可以实现MessageListener接口,这样可以不用通过@MessageDriven设置间接的实现的接口。
@EJB(name = "StudentBean") private Student student; public void onMessage(Message msg) { try { if (msg instanceof TextMessage) { TextMessage txt = (TextMessage) msg; String content = txt.getText(); System.out.println("the message is " + content); student.say(content); } else if (msg instanceof MapMessage) { MapMessage map = (MapMessage) msg; String name = map.getString("name"); int age = map.getInt("age"); System.out.println(name + "\t" + age); } } catch (JMSException e) { e.printStackTrace(); } }
上面的例子使用@EJB来修饰student,告诉EJB容器应将名为“StudentBean”的EJB注入该Field。