Eclipse+JBoss+EJB3消息驱动Bean

开发 后端
本文讲述Eclipse+JBoss+EJB3消息驱动Bean。在前面的文章中给出的SessionBean的例子都是同步调用SessionBean方法的。在某些情况下,由于SessionBean方法的执行时间比较长,这就需要异步地调用该方法。

在前面的文章中给出的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;  
    }  
      
}  
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

二、编写消息驱动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);  
        }  
 
    }  
 
}  
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.

消息驱动Bean需要使用@MessageDriven进行注释。要注意的是destination属性的值是queue/MDBQueue。JBoss不会自已建立一个Queue对象,因此,需要手工来配置Queue对象。读者可以\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=DestinationManagerdepends> 
  < mbean> 
< server> 
     
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

要注意的是,元素的name属性值中的name必须是MDBQueue,要与queue/MDBQueue中的/后面的部分一致。如果不进行上面的配置,在启动JBOSS时就会抛出如下的异常:

javax.naming.NameNotFoundException: MDBQueue not bound

也可以将元素放在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' 
... ... 
  • 1.
  • 2.

三、编写调用消息驱动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 "方法成功返回";  
 
    }  
}  
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.

在上面的代码中使用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("成功发送消息!");  
    }  
}  
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

【编辑推荐】

  1. Eclipse+JBoss+EJB3通过继承实体Bean将单个表映射成多个表
  2. Eclipse+JBoss+EJB3实现Entity Bean的多对多映射
  3. Eclipse+JBoss+EJB3在Servlet中访问EntityManager对象
  4. Eclipse+JBoss+EJB3使用命名查询执行JPQL
  5. Eclipse+JBoss+EJB3实体Bean的连接策略
责任编辑:book05 来源: BlogJava
相关推荐

2009-06-24 15:56:47

实体Bean连接策略

2009-06-10 11:42:26

Session BeaEclipse+JBo

2009-06-10 11:09:40

配置文件SessionEclipse+JBo

2009-06-10 12:34:01

Session BeaEclipse+JBo

2009-06-24 15:53:08

Entity Bean多对多映射

2009-06-10 11:36:45

有状态的SessionEclipse+JBo

2009-06-24 15:47:13

实体Bean

2009-06-24 15:51:47

Entity Bean一对多映射

2009-06-24 15:57:44

JPQL命名查询

2009-06-24 15:49:54

Entity Bean一对一映射

2009-06-24 15:58:15

EntityManag

2009-06-24 15:55:09

EclipseJBossJ2ee

2009-06-24 16:00:00

2009-06-10 12:54:35

无状态的SessionEclipse+JBo

2009-06-15 16:06:25

JBoss IDE

2009-09-24 12:05:35

2009-06-17 08:51:26

Eclipse启动JB

2009-06-17 09:01:20

JBoss访问EJB

2009-06-16 15:15:18

WebLogic EJ

2009-06-29 17:07:54

EJB部署Jboss
点赞
收藏

51CTO技术栈公众号