本文為原創(chuàng),如需轉(zhuǎn)載,請(qǐng)注明作者和出處,謝謝!
上一篇:
eclipse + JBoss 5 + EJB3開發(fā)指南(13):在Servlet中訪問應(yīng)用程序管制EntityManager對(duì)象
在前面的文章中給出的SessionBean的例子都是同步調(diào)用SessionBean方法的,也就是說(shuō),只有當(dāng)方法中的代碼都執(zhí)行完,才能返回到客戶端。但在某些情況下,由于SessionBean方法的執(zhí)行時(shí)間比較長(zhǎng),這就需要異步地調(diào)用該方法,否則客戶端就需要等待比較長(zhǎng)的時(shí)間。要實(shí)現(xiàn)異步調(diào)用,就需要使用本要講的消息驅(qū)動(dòng)Bean。消息驅(qū)動(dòng)Bean的基本原理是客戶端向消息服務(wù)器發(fā)送一條消息后,消息服務(wù)器會(huì)將該消息保存在消息隊(duì)列中。在這時(shí)消息服務(wù)器中的某個(gè)消費(fèi)者(讀取并處理消息的對(duì)象)會(huì)讀取該消息,并進(jìn)行處理。發(fā)送消息的客戶端被稱為消息生產(chǎn)者。
本文給出的消息驅(qū)動(dòng)Bean的例子的基本功能是客戶端向消息服務(wù)器發(fā)送一條消息(該消息實(shí)際上是一個(gè)實(shí)體Bean的對(duì)象實(shí)例),然后消息消費(fèi)者讀取這條消息后,將消息中的實(shí)體Bean持久化。實(shí)現(xiàn)消息驅(qū)動(dòng)Bean的步驟如下:
一、實(shí)現(xiàn)實(shí)體Bean
package entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="t_date")
public class DateBean implements Serializable
{
private int id;
private Date myDate;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
@Column(name="mydate")
public Date getMyDate()
{
return myDate;
}
public void setMyDate(Date myDate)
{
this.myDate = myDate;
}
}
二、編寫消息驅(qū)動(dòng)Bean
消息驅(qū)動(dòng)Bean必須實(shí)現(xiàn)MessageListener接口,當(dāng)該消息驅(qū)動(dòng)Bean接收到一個(gè)消息后,EJB容器就會(huì)調(diào)用MessageListener接口的onMessage方法來(lái)理該消息。消息驅(qū)動(dòng)Bean的代碼如下:
package service;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.EJBException;
import javax.ejb.MessageDriven;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import entity.DateBean;
@MessageDriven( activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/MDBQueue")
})
public class DateMessageBean implements MessageListener
{
@PersistenceContext(unitName = "myentity1")
private EntityManager em;
@Override
public void onMessage(Message message)
{
try
{
if(message instanceof ObjectMessage)
{
ObjectMessage objmsg = (ObjectMessage) message;
DateBean dateBean = (DateBean) objmsg.getObject();
em.persist(dateBean);
System.out.println("成功持久化DateBean對(duì)象!");
}
else
{
System.out.println("消息類型錯(cuò)誤!");
}
}
catch (Exception e)
{
throw new EJBException(e);
}
}
}
消息驅(qū)動(dòng)Bean需要使用
@MessageDriven進(jìn)行注釋。要注意的是destination屬性的值是queue/MDBQueue。JBoss不會(huì)自已建立一個(gè)Queue對(duì)象,因此,需要手工來(lái)配置Queue對(duì)象。讀者可以<JBoss5.x安裝目錄>\server\default\deploy目錄中建立一個(gè)xxx-service.xml文件,其中xxx可以任意取值,但必須跟“-service”后綴,例如,abc-service.xml。該文件可以放在deploy或其子目錄(可以是多層子目錄)中。該文件的內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=MDBQueue">
<depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
</mbean>
</server>
要注意的是,<mbean>元素的name屬性值中的name必須是MDBQueue,要與queue/MDBQueue中的/后面的部分一致。如果不進(jìn)行上面的配置,在啟動(dòng)JBOSS時(shí)就會(huì)拋出如下的異常:
javax.naming.NameNotFoundException: MDBQueue not bound
也可以將<mbean>元素放在deploy目錄中的其他以-service.xml結(jié)尾的文件中。
如果不設(shè)置destination屬性的值,在啟動(dòng)JBoss是會(huì)拋出如下的異常:
org.jboss.deployers.spi.DeploymentException: Required config property RequiredConfigPropertyMetaData@174098f[name=destination descriptions=[DescriptionMetaData@4ca30b[language=zh]]] for messagingType 'javax.jms.MessageListener' not found in activation config [ActivationConfigProperty(destinationType=javax.jms.Queue), ActivationConfigProperty(connectionFactoryJndiName=MyQueueConnectionFactory), ActivationConfigProperty(destinationName=MyRequestQueue)] ra=jboss.jca:service=RARDeployment,name='jms-ra.rar'
... ...
三、編寫調(diào)用消息驅(qū)動(dòng)Bean的SessionBean
package service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.Session;
import javax.persistence.EntityManager;
import entity.DateBean;
import entity.Greeting;
@Stateless
public class GreeterBean implements Greeter
{
@Resource(mappedName = "ConnectionFactory")
private ConnectionFactory cf;
@Resource(mappedName = "queue/MDBQueue")
private Queue queue;
@Override
public String greet(String message)
{
try
{
DateBean db = new DateBean();
db.setMyDate(new Date());
Connection connection = cf.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(queue);
ObjectMessage objectMessage = session.createObjectMessage();
objectMessage.setObject(db);
messageProducer.send(objectMessage);
connection.close();
System.out.println("成功發(fā)送消息!");
}
catch (Exception e)
{
System.out.println("發(fā)送消息失敗!");
}
return "方法成功返回";
}
}
在上面的代碼中使用ObjectMessage對(duì)象來(lái)包裝要向消息服務(wù)器發(fā)送的實(shí)體Bean的對(duì)象實(shí)例。
除了可以在SessionBean中訪問消息驅(qū)動(dòng)Bean外,還可以在不同的機(jī)器上通過jndi來(lái)查找并調(diào)用消息驅(qū)動(dòng)Bean,代碼如下:
package test;
import java.util.Date;
import javax.ejb.EJB;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSession;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import entity.DateBean;
import service.Greeter;
public class Client
{
public static void main(String[] args) throws Exception
{
InitialContext ctx = new InitialContext();
QueueConnection connection = null;
QueueSession session = null;
QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("ConnectionFactory");
connection = factory.createQueueConnection();
session = connection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
Destination destination = (Queue) ctx.lookup("queue/MDBQueue");
MessageProducer messageProducer = session.createProducer(destination);
ObjectMessage objectMessage = session.createObjectMessage();
DateBean db = new DateBean();
db.setMyDate(new Date());
objectMessage.setObject(db);
messageProducer.send(objectMessage);
connection.close();
System.out.println("成功發(fā)送消息!");
}
}
下一篇:
eclipse + JBoss 5 + EJB3開發(fā)指南(15):攔截器方法和攔截器類
新浪微博:http://t.sina.com.cn/androidguy 昵稱:李寧_Lining