您的位置:首页 > 编程语言 > Java开发

eclipse + JBoss 5 + EJB3开发指南(14):消息驱动Bean

2009-06-08 23:49 731 查看
本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:eclipse + JBoss 5 + EJB3开发指南(13):在Servlet中访问应用程序管制EntityManager对象

在前面的文章中给出的SessionBean的例子都是同步调用SessionBean方法的,也就是说,只有当方法中的代码都执行完,才能返回到客户端。但在某些情况下,由于SessionBean方法的执行时间比较长,这就需要异步地调用该方法,否则客户端就需要等待比较长的时间。要实现异步调用,就需要使用本要讲的消息驱动Bean。消息驱动Bean的基本原理是客户端向消息服务器发送一条消息后,消息服务器会将该消息保存在消息队列中。在这时消息服务器中的某个消费者(读取并处理消息的对象)会读取该消息,并进行处理。发送消息的客户端被称为消息生产者。

本文给出的消息驱动Bean的例子的基本功能是客户端向消息服务器发送一条消息(该消息实际上是一个实体Bean的对象实例),然后消息消费者读取这条消息后,将消息中的实体Bean持久化。实现消息驱动Bean的步骤如下:

一、实现实体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;

}



}

二、编写消息驱动Bean

消息驱动Bean必须实现MessageListener接口,当该消息驱动Bean接收到一个消息后,EJB容器就会调用MessageListener接口的onMessage方法来理该消息。消息驱动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对象!");

}

else

{

System.out.println("消息类型错误!");

}

}

catch (Exception e)

{

throw new EJBException(e);

}

}

}

消息驱动Bean需要使用@MessageDriven进行注释。要注意的是destination属性的值是queue/MDBQueue。JBoss不会自已建立一个Queue对象,因此,需要手工来配置Queue对象。读者可以<JBoss5.x安装目录>/server/default/deploy目录中建立一个xxx-service.xml文件,其中xxx可以任意取值,但必须跟“-service”后缀,例如,abc-service.xml。该文件可以放在deploy或其子目录(可以是多层子目录)中。该文件的内容如下:

<?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中的/后面的部分一致。如果不进行上面的配置,在启动JBOSS时就会抛出如下的异常:

javax.naming.NameNotFoundException: MDBQueue not bound

也可以将<mbean>元素放在deploy目录中的其他以-service.xml结尾的文件中。

如果不设置destination属性的值,在启动JBoss是会抛出如下的异常:

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'

... ...



三、编写调用消息驱动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("成功发送消息!");

}

catch (Exception e)

{

System.out.println("发送消息失败!");

}

return "方法成功返回";

}

}

在上面的代码中使用ObjectMessage对象来包装要向消息服务器发送的实体Bean的对象实例。

除了可以在SessionBean中访问消息驱动Bean外,还可以在不同的机器上通过jndi来查找并调用消息驱动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("成功发送消息!");

}

}

下一篇:eclipse + JBoss 5 + EJB3开发指南(15):拦截器方法和拦截器类

国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐