J2EE 1.4 引入重大消息領域更新:統一 JMS 1.1 API、收緊容器使用限制、引入 message-destination 解耦生產消費配置、重構 MDB 部署描述符以支持非 JMS 協議。本文為遷移現有應用或新建項目提供完整參考。
核心變化:Queue (PTP) 與 Topic (Pub/Sub) 接口統一為 ConnectionFactory、Destination、Connection、Session、MessageProducer、MessageConsumer。完全向後兼容,舊代碼無需修改;新代碼強烈建議僅使用統一接口。
InitialContext ctx = new InitialContext();
ConnectionFactory cf = (ConnectionFactory) ctx.lookup("java:comp/env/jms/cf");
Destination src = (Destination) ctx.lookup("java:comp/env/jms/source");
Connection conn = cf.createConnection();
conn.start();
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer consumer = sess.createConsumer(src);
Message msg = consumer.receive();
conn.close();
javax.jms.ServerSessionjavax.jms.ServerSessionPooljavax.jms.ConnectionConsumerjavax.jms.XA* 介面Session.run()
QueueConnection.createConnectionConsumer()
TopicConnection.createConnectionConsumer()
TopicConnection.createDurableConnectionConsumer()
MessageConsumer.setMessageListener() / getMessageListener()
Connection.setExceptionListener() / stop() / setClientID()
關鍵影響:不能在 Servlet/EJB 中註冊 MessageListener (異步回調)。原因:JMS Provider 回調線程無容器上下文 (事務、安全 Principal)。替代方案:同步 receive() 輪詢、或改用 Message-Driven Bean (MDB) 由容器管理監聽。
createSession() 後,必須 close() 原 Session 才能再次創建,否則拋異常。close() (容器連接池使開銷可接受)。痛點:J2EE 1.3 用 resource-env-ref 定義目標,生產者查 jms/target,消費者查 jms/source,部署描述符無機制表達「它們綁定同一物理 Queue」。
message-destination-ref:替代 resource-env-ref,新增兩子元素:
message-destination-usage:Produces / Consumes / ProducesConsumes —— 聲明用途,部署員據此配對。message-destination-link:邏輯名,關聯到組裝描述符中的 message-destination。message-destination (在 <assembly-descriptor> 中):邏輯目標定義,部署員將其綁定到物理 JMS Queue/Topic。J2EE 1.3 (雙 ref,部署員靠文檔/口頭協調綁定同一 Queue)
<resource-env-ref><resource-env-ref-name>jms/target</...><resource-env-ref-type>javax.jms.Queue</...></resource-env-ref> // Sender
<resource-env-ref><resource-env-ref-name>jms/source</...><resource-env-ref-type>javax.jms.Queue</...></resource-env-ref> // Receiver
J2EE 1.4 (單一 message-destination,意圖顯式)
<message-destination-ref> // Sender
<message-destination-ref-name>jms/target</...>
<message-destination-type>javax.jms.Queue</...>
<message-destination-usage>Produces</...>
<message-destination-link>destination</...>
</message-destination-ref>
<message-destination-ref> // Receiver
<message-destination-ref-name>jms/source</...>
<message-destination-type>javax.jms.Queue</...>
<message-destination-usage>Consumes</...>
<message-destination-link>destination</...>
</message-destination-ref>
<assembly-descriptor>
<message-destination><message-destination-name>destination</...></message-destination>
</assembly-descriptor>
部署員僅需一個綁定:將 destination 映射到物理 Queue。支持跨 JAR 模塊鏈接 (../other/other.jar#destination)。
javax.jms.MessageListener新增 <messaging-type> 元素聲明實現接口 (如 javax.jms.MessageListener),為未來非 JMS 協議 (如 JCA 入站) 鋪路。現有 JMS MDB 代碼無需改動。
activation-config 名值對| EJB 2.0 專用元素 | EJB 2.1 activation-config-property-name (建議值) |
|---|---|
<acknowledge-mode> | acknowledgeMode (Auto-acknowledge / Dups-ok-acknowledge) |
<destination-type> | destinationType (javax.jms.Queue / javax.jms.Topic) |
<subscription-durability> | subscriptionDurability (NonDurable / Durable) |
<message-selector> | messageSelector (String 選擇器) |
機制:JMS Provider 提供 ActivationSpec JavaBean,屬性即上述名稱。部署描述符中的值覆蓋管理員默認值。屬性僅為建議,具體以 Provider 文檔為準。
message-destination-link 直接綁定目標<message-driven>
<message-destination-type>javax.jms.Queue</...>
<message-destination-link>destination</...> <!-- 直接關聯 assembly-descriptor 中的邏輯目標 -->
<activation-config>...</activation-config>
</message-driven>
運行時容器解析 Link → 物理 Destination 對象 → 注入 ActivationSpec.destination (若 Provider 支持 javax.jms.Destination 類型屬性)。
setMessageListener 等) → 改同步 receive() 或遷移至 MDB。resource-env-ref 遷移為 message-destination-ref + message-destination。messaging-type、用 activation-config 替換舊屬性、可選加 message-destination-link。ActivationSpec 支持哪些屬性名/值。J2EE 1.4 消息更新雖帶來遷移工作,但統一 API、解耦配置、MDB 協議中立化,奠定了現代 Java 消息開發基石。掌握上述變化,能平滑遷移並發揮新特性優勢。