程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> eclipse + JBoss 5 + EJB3開發指南(14):消息驅動Bean

eclipse + JBoss 5 + EJB3開發指南(14):消息驅動Bean

編輯:關於JAVA

在前面的文章中給出的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("成功發送消息!");
    }
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved