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

简介:
 在前面的文章中给出的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(
" 成功发送消息! " );
    }
}




 本文转自 androidguy 51CTO博客,原文链接:http://blog.51cto.com/androidguy/214419,如需转载请自行联系原作者
相关文章
|
Java 应用服务中间件 Android开发
【EJB学习笔记】——EJB开发环境搭建(Eclipse集成JBoss)
  之前一直用的EJB开发环境是他们搭建好的,直接拿来用,不过还是感觉老吃别人嚼好的不太好吃,所以自己动手来玩一玩。   EJB开发依赖的最基本的环境:JDK、Eclipse、JBoss,这里简单介绍一下最基本的环境的搭建。
【EJB学习笔记】——EJB开发环境搭建(Eclipse集成JBoss)
|
Android开发
使用Eclipse连接SAP Netweaver系统遇到的错误消息和解决办法
使用Eclipse连接SAP Netweaver系统遇到的错误消息和解决办法
148 0
使用Eclipse连接SAP Netweaver系统遇到的错误消息和解决办法
|
Java 数据库连接 应用服务中间件
怎样在eclipse里安装Hibernate / JBoss 工具【最新】
原文:http://www.mkyong.com/hibernate/how-to-install-hibernate-tools-in-eclipse-ide/
202 0
怎样在eclipse里安装Hibernate / JBoss 工具【最新】
|
Java Android开发
如何处理Eclipse错误消息 The declared package does not match the expected package
如何处理Eclipse错误消息 The declared package does not match the expected package
229 0
|
IDE 应用服务中间件 开发工具

推荐镜像

更多