到目前为止前面介绍的有关JavaEE的东西都是同步的,也就是说调用者调用某个方法,那么这个方法必须立即执行并返回执行结果。用官方一些的语言来说就是“客户端通过业务接口调用一个方法,在将控制权返回给客户端之前,服务器完成该方法调用”。对于我们接触到的大多数操作而言这是最自然也是最容易实现的方法。然而,有些情况下客户端并不需要等待服务器响应,而只需要告诉服务器应该做什么就可以了,在完成“告知”任务之后客户端能够继续工作,而服务器则默默的在一旁处理客户端的请求(通常会是很多客户端,很多请求)。
在JavaEE中对于消息的处理有其自身的解决办法——消息驱动bean(Message-Driven Bean,MDB)。它是JavaEE中用于异步消息传递的EJB组件,使用消息驱动bean可以实现上文中所说的客户端在请求服务器之后还能够继续正常的工作。客户端利用消息(JMS?)向服务器发出请求,当然这些请求最终是要交付给MDB来处理的。每当服务器收到请求时,将调用MDB的业务接口(这里有点儿类似于会话bean,但是这里的接口并不是开发人员添加的),进而对应的实现者会做相应的处理。
就像前面博文中说的那样,当使用一个会话bean时,开发人员通常会创建一个业务接口,并在bean类中实现它(尽管你完全可以采用无接口的方式调用会话bean)。但是对于消息驱动bean来说,它需要实现一个特定于MDB所基于的消息系统的接口。这句话有些拗口,简而言之就是用哪种类型的消息机制就需要实现其相应的接口。这里以JMS为例子,当然JMS也是最常见的情况,(需要注意的是其他基于Java连接器体系结构(Java ConnectorArchitecture,简称JCA)的消息传递系统也是可以实现消息传递的)。对于JMS消息驱动bean来说,他的业务接口是javax.jms.MessageListener,其中定义了单一方法:onMessage()。
下面代码示例显示了一个消息驱动bean(采用JMS方式)的基本结构。
@MessageDriven(
mappedName="destinationQueue",
activationConfig = {
@ActivationConfigProperty(propertyName="destinationType",
propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="messageSelector",
propertyValue="RECIPIENT='ReportProcessor'")
})
public class ReportProcessorBean implements javax.jms.MessageListener {
public void onMessage(javax.jms.Message message) {
try {
System.out.println("Processing message: " + ((TextMessage) message).getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
在本例中对于上面的消息驱动bean他的消息产生是来源于一个Servlet(核心代码如下)
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
printHtmlHeader(out);
// if there was info submitted, send the message
String messageText = request.getParameter("message");
if (messageText != null) {
try {
QueueConnectionFactory factory = (QueueConnectionFactory)
new InitialContext().lookup("java:comp/env/jms/MyQueueConnectionFactory");
Queue destinationQueue = (Queue)
new InitialContext().lookup("java:comp/env/jms/MyQueue");
QueueConnection connection = factory.createQueueConnection();
QueueSession session = connection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
QueueSender sender = session.createSender(null);
Message message = session.createTextMessage(messageText);
message.setStringProperty("RECIPIENT", "ReportProcessor");
sender.send(destinationQueue, message);
connection.close();
// print a response to the html stream
out.println("Message \"" + messageText + "\" sent! See the console " +
"or the log file at <EXAMPLES_HOME>/glassfish/domains/domain1/logs/server.log.");
} catch (Exception e) {
throw new ServletException(e);
}
}
printHtmlFooter(out);
}
@MessageDriven注解把类标记为一个MDB。由@ActivationConfigProperty注解所定义的激活配置属性,将通知服务器该消息传递系统的类型(以Queue的方式)以及该系统所需要的任何配置的详细信息。在这种情况下,只有当JMS消息有一个名为RECIPIENT的属性,且其值为ReprotProcessor时,才会调用MDB。这个例子中需要在服务器中做JMS的配置。相应的每当服务器接受一个消息时,它将把消息作为参数调用onMessage()方法。因为与客户端没有任何同步连接,所以onMessage()方法不会返回任何内容。
对于消息驱动bean来说只需要知道他的两个标签即可:异步,消息。