随笔 - 312, 文章 - 14, 评论 - 1393, 引用 - 0

导航

<2009年6月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

公告

关注我的新浪微博

我的著作









常用链接

留言簿(126)

我参与的团队

随笔分类(818)

随笔档案(310)

文章分类(1)

文章档案(8)

相册

ADSL、3G查询

CSDN

eclipse

ibm

Java EE

Linux

Web

云服务

代理网站

关注的网站

协议

喜欢的Blog

国内广告平台

图书出版

在线培训

开发工具

微博客户端

手机铃声

操作系统

  • ReactOS
  • 一个与windowXP/2003兼容的操作系统

数学

文件格式

源码资源

移动(Mobile)

编程语言

英语学习

最新随笔

搜索

  •  

积分与排名

  • 积分 - 1969740
  • 排名 - 6

最新评论

阅读排行榜

评论排行榜

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

本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇: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):拦截器方法和拦截器类





Android开发完全讲义(第2版)(本书版权已输出到台湾)

http://product.dangdang.com/product.aspx?product_id=22741502



Android高薪之路:Android程序员面试宝典 http://book.360buy.com/10970314.html


新浪微博:http://t.sina.com.cn/androidguy   昵称:李宁_Lining

posted on 2009-06-08 23:40 银河使者 阅读(2472) 评论(0)  编辑  收藏 所属分类: java 原创ejb3JBoss


只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问