首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

EJB 3 開發指南(14):訊息驅動 Bean (MDB) 完整實作教學

     編輯:Java 相關知識

當業務處理耗時較長(如報表生成、郵件發送、資料同步)時,同步呼叫會阻塞客戶端。EJB 3 的訊息驅動 Bean (Message-Driven Bean, MDB) 結合 JMS 佇列,實現非同步處理架構。本文完整示範:實體 Bean 持久化、MDB 接收處理、Session Bean 發送訊息、獨立客戶端發送訊息的端到端流程。

架構概覽

客戶端 / Session Bean
      │ 發送 ObjectMessage (包含實體 Bean)
      ▼
JMS Queue (MDBQueue)
      │ 容器自動監聽
      ▼
Message-Driven Bean (onMessage)
      │ 解析實體 → EntityManager.persist()
      ▼
資料庫持久化完成

一、實體 Bean:DateBean

@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:DateMessageBean

@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);
        }
    }
}

關鍵配置說明

  • destinationType=javax.jms.Queue:使用點對點佇列模式
  • destination=queue/MDBQueue:JNDI 名稱,需在 JBoss 手動建立對應 Queue

JBoss 建立 Queue 設定

在 $JBOSS_HOME/server/default/deploy 建立 mdb-service.xml(檔名須以 -service.xml 結尾):

<?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>

注意:name 屬性中的 name=MDBQueue 必須與 queue/MDBQueue 斜線後一致,否則啟動拋出 NameNotFoundException: MDBQueue not bound。

三、Session Bean 發送訊息:GreeterBean

@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 conn = cf.createConnection();
            Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
            MessageProducer producer = session.createProducer(queue);
            ObjectMessage objMsg = session.createObjectMessage();
            objMsg.setObject(db);
            producer.send(objMsg);
            conn.close();

            System.out.println("成功發送訊息!");
        } catch (Exception e) {
            System.out.println("發送訊息失敗!");
        }
        return "方法成功返回";
    }
}

四、獨立 Java 客戶端發送訊息

public class Client {
    public static void main(String[] args) throws Exception {
        InitialContext ctx = new InitialContext();
        QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("ConnectionFactory");
        QueueConnection conn = factory.createQueueConnection();
        QueueSession session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
        Destination dest = (Queue) ctx.lookup("queue/MDBQueue");
        MessageProducer producer = session.createProducer(dest);
        ObjectMessage objMsg = session.createObjectMessage();
        DateBean db = new DateBean();
        db.setMyDate(new Date());
        objMsg.setObject(db);
        producer.send(objMsg);
        conn.close();
        System.out.println("成功發送訊息!");
    }
}

常見錯誤與解決

錯誤現象原因解決
NameNotFoundException: MDBQueue not bound未建立 Queue 或 JNDI 名稱不匹配依上方 mdb-service.xml 建立 Queue,確認 name 屬性
Required config property 'destination' not found@MessageDriven 缺少 destination 設定補上 activationConfig 的 destination 屬性
訊息收不到ObjectMessage 類別未實作 Serializable實體 Bean 必須 implements Serializable

非同步處理優勢

  • 客戶端發送訊息後立即返回,無需等待業務完成
  • 訊息堆疊於 Queue,尖峰流量自動緩衝
  • MDB 可配置多實例並行消費(@ActivationConfigProperty(propertyName="maxSession", propertyValue="10"))
  • 支援交易回滾:onMessage 拋出異常時,訊息可重新投遞(需配置 Redelivery)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved