使用 Spring JMS

本節介紹如何使用 Spring 的 JMS 元件。

JmsTemplateJmsClient

JmsTemplate 類是 JMS 核心包中的核心類。它簡化了 JMS 的使用,因為它在傳送或同步接收訊息時處理資源的建立和釋放。

JmsClient 是 Spring Framework 7.0 中新的 API 變體,遵循 JdbcClient 等設計。JmsClient 構建於 JmsTemplate 之上,用於簡單的傳送和接收操作,並提供每個操作的自定義選項。

使用 JmsTemplate

使用 JmsTemplate 的程式碼只需要實現回撥介面,這些介面提供了明確定義的高階契約。MessageCreator 回撥介面在給定 JmsTemplate 中呼叫程式碼提供的 Session 時建立訊息。為了更復雜地使用 JMS API,SessionCallback 提供 JMS 會話,ProducerCallback 暴露 SessionMessageProducer 對。

JMS API 暴露兩種型別的傳送方法,一種接收傳輸模式、優先順序和生存時間作為服務質量 (QOS) 引數,另一種不接收 QOS 引數並使用預設值。由於 JmsTemplate 有許多傳送方法,因此將 QOS 引數設定為 bean 屬性,以避免傳送方法數量的重複。同樣,同步接收呼叫的超時值透過使用 setReceiveTimeout 屬性設定。

一些 JMS 提供者允許透過配置 ConnectionFactory 以管理方式設定預設 QOS 值。這導致對 MessageProducer 例項的 send 方法 (send(Destination destination, Message message)) 的呼叫使用與 JMS 規範中指定的 QOS 預設值不同的值。為了提供一致的 QOS 值管理,JmsTemplate 必須透過將布林屬性 isExplicitQosEnabled 設定為 true 來明確啟用使用其自己的 QOS 值。

為方便起見,JmsTemplate 還暴露一個基本的請求-回覆操作,允許傳送訊息並等待在作為操作一部分建立的臨時佇列上進行回覆。

JmsTemplate 類的例項一旦配置,就是執行緒安全的。這很重要,因為這意味著您可以配置 JmsTemplate 的單個例項,然後安全地將此共享引用注入到多個協作器中。明確地說,JmsTemplate 是有狀態的,因為它維護對 ConnectionFactory 的引用,但此狀態不是會話狀態。

使用 JmsClient

從 Spring Framework 4.1 開始,JmsMessagingTemplate 構建在 JmsTemplate 之上,並與 Spring 的通用訊息抽象整合,即處理 org.springframework.messaging.Message 進行傳送和接收,丟擲 org.springframework.messaging.MessagingException,並透過 org.springframework.messaging.converter.MessageConverter 進行負載轉換(有許多常見的轉換器實現可用)。

從 Spring Framework 7.0 開始,提供了一個名為 JmsClient 的流暢 API。這提供了圍繞 org.springframework.messaging.Message 的可自定義操作並丟擲 org.springframework.messaging.MessagingException,類似於 JmsMessagingTemplate,以及與 org.springframework.messaging.converter.MessageConverter 的整合。JmsClient 可以為給定的 ConnectionFactory 或給定的 JmsTemplate 建立,在後一種情況下預設重用其設定。有關使用示例,請參閱 JmsClient

連線

JmsTemplate 需要引用 ConnectionFactoryConnectionFactory 是 JMS 規範的一部分,作為使用 JMS 的入口點。客戶端應用程式使用它作為工廠來建立與 JMS 提供者的連線,並封裝各種配置引數,其中許多是特定於供應商的,例如 SSL 配置選項。

在 EJB 中使用 JMS 時,供應商提供 JMS 介面的實現,以便它們可以參與宣告式事務管理並執行連線和會話的池化。為了在 EJB 中使用 JmsTemplate 利用此實現,Jakarta EE 容器通常要求您在 EJB 或 servlet 部署描述符中將 JMS 連線工廠宣告為 resource-ref。為確保在 EJB 中使用 JmsTemplate 的這些功能,客戶端應用程式應確保它引用 ConnectionFactory 的託管實現。

快取訊息資源

標準 API 涉及建立許多中間物件。要傳送訊息,執行以下“API”步驟

ConnectionFactory->Connection->Session->MessageProducer->send

ConnectionFactorySend 操作之間,建立並銷燬了三個中間物件。為了最佳化資源使用並提高效能,Spring 提供了 ConnectionFactory 的兩種實現。

使用 SingleConnectionFactory

Spring 提供了 ConnectionFactory 介面的一個實現,SingleConnectionFactory,它在所有 createConnection() 呼叫上返回相同的 Connection 並忽略對 close() 的呼叫。這對於測試和獨立環境很有用,因此可以為跨任意數量事務的多個 JmsTemplate 呼叫使用相同的連線。SingleConnectionFactory 引用通常來自 JNDI 的標準 ConnectionFactory

使用 CachingConnectionFactory

CachingConnectionFactory 擴充套件了 SingleConnectionFactory 的功能,並增加了 SessionMessageProducerMessageConsumer 例項的快取。初始快取大小設定為 1。您可以使用 sessionCacheSize 屬性增加快取會話的數量。請注意,實際快取的會話數量多於該數字,因為會話是根據其確認模式進行快取的,因此當 sessionCacheSize 設定為 1 時,最多可以有四個快取會話例項(每種確認模式一個)。MessageProducerMessageConsumer 例項在其擁有的會話中快取,並在快取時也考慮生產者和消費者的獨特屬性。MessageProducers 根據其目標進行快取。MessageConsumers 根據由目標、選擇器、noLocal 傳輸標誌和持久訂閱名稱(如果建立持久消費者)組成的鍵進行快取。

臨時佇列和主題(TemporaryQueue/TemporaryTopic)的 MessageProducer 和 MessageConsumer 永遠不會被快取。不幸的是,WebLogic JMS 恰好在其常規目標實現上實現了臨時佇列/主題介面,錯誤地指示其所有目標都無法快取。請在 WebLogic 上使用不同的連線池/快取,或為 WebLogic 目的自定義 CachingConnectionFactory

目標管理

目標,作為 ConnectionFactory 例項,是 JMS 管理物件,您可以將其儲存和檢索在 JNDI 中。配置 Spring 應用程式上下文時,可以使用 JNDI JndiObjectFactoryBean 工廠類或 <jee:jndi-lookup> 對物件的 JMS 目標引用執行依賴注入。然而,如果應用程式中有大量目標,或者 JMS 提供者具有獨特的先進目標管理功能,這種策略通常很繁瑣。此類先進目標管理的示例包括動態目標的建立或對分層目標名稱空間的支援。JmsTemplate 將目標名稱的解析委託給實現 DestinationResolver 介面的 JMS 目標物件。DynamicDestinationResolverJmsTemplate 使用的預設實現,用於解析動態目標。還提供了 JndiDestinationResolver,作為 JNDI 中包含的目標的服務定位器,並可選擇回退到 DynamicDestinationResolver 中包含的行為。

通常,JMS 應用程式中使用的目標只有在執行時才知道,因此在部署應用程式時無法管理地建立。這通常是因為互動系統元件之間存在共享應用程式邏輯,這些元件根據眾所周知的命名約定在執行時建立目標。儘管動態目標的建立不是 JMS 規範的一部分,但大多數供應商都提供了此功能。動態目標以使用者定義名稱建立,這使其與臨時目標區分開來,並且通常未在 JNDI 中註冊。用於建立動態目標的 API 因提供者而異,因為與目標關聯的屬性是供應商特定的。然而,供應商有時會做出一個簡單的實現選擇,即忽略 JMS 規範中的警告,並使用方法 TopicSession createTopic(String topicName)QueueSession createQueue(String queueName) 方法建立具有預設目標屬性的新目標。根據供應商實現,DynamicDestinationResolver 也可以建立物理目標,而不僅僅是解析一個。

布林屬性 pubSubDomain 用於配置 JmsTemplate,使其瞭解正在使用的 JMS 域。預設情況下,此屬性的值為 false,表示將使用點對點域 Queues。此屬性(由 JmsTemplate 使用)決定透過 DestinationResolver 介面的實現進行動態目標解析的行為。

您還可以透過屬性 defaultDestinationJmsTemplate 配置預設目標。預設目標用於不引用特定目標的傳送和接收操作。

訊息監聽器容器

在 EJB 世界中,JMS 訊息最常見的用途之一是驅動訊息驅動 bean (MDB)。Spring 提供了一種建立訊息驅動 POJO (MDP) 的解決方案,這種方式不會將使用者繫結到 EJB 容器。(有關 Spring 對 MDP 支援的詳細介紹,請參閱非同步接收:訊息驅動 POJO。)端點方法可以使用 @JmsListener 進行註解——有關更多詳細資訊,請參閱註解驅動的監聽器端點

訊息監聽器容器用於從 JMS 訊息佇列接收訊息並驅動注入其中的 MessageListener。監聽器容器負責所有訊息接收的執行緒化並將訊息分派到監聽器進行處理。訊息監聽器容器是 MDP 和訊息提供者之間的中介軟體,負責註冊接收訊息、參與事務、資源獲取和釋放、異常轉換等。這使您可以編寫與接收訊息(並可能對其進行響應)相關的(可能複雜的)業務邏輯,並將樣板 JMS 基礎設施問題委託給框架。

Spring 中打包了兩種標準 JMS 訊息監聽器容器,每種都具有其專門的功能集。

使用 SimpleMessageListenerContainer

此訊息監聽器容器是兩種標準型別中較簡單的一種。它在啟動時建立固定數量的 JMS 會話和消費者,使用標準 JMS MessageConsumer.setMessageListener() 方法註冊監聽器,並將監聽器回撥留給 JMS 提供者執行。此變體不允許動態適應執行時需求或參與外部管理的事務。從相容性角度來看,它非常接近獨立 JMS 規範的精神,但通常與 Jakarta EE 的 JMS 限制不相容。

雖然 SimpleMessageListenerContainer 不允許參與外部管理的事務,但它支援原生 JMS 事務。要啟用此功能,可以將 sessionTransacted 標誌切換為 true,或者在 XML 名稱空間中,將 acknowledge 屬性設定為 transacted。從監聽器丟擲的異常將導致回滾,訊息會重新傳遞。或者,考慮使用 CLIENT_ACKNOWLEDGE 模式,該模式在發生異常時也提供重新傳遞,但它不使用事務性 Session 例項,因此不包括事務協議中的任何其他 Session 操作(例如傳送響應訊息)。
預設的 AUTO_ACKNOWLEDGE 模式不提供適當的可靠性保證。當監聽器執行失敗(因為提供者在監聽器呼叫後自動確認每條訊息,沒有異常傳播到提供者)或當監聽器容器關閉(您可以透過設定 acceptMessagesWhileStopping 標誌來配置此行為)時,訊息可能會丟失。在需要可靠性時(例如,用於可靠的佇列處理和持久主題訂閱),請務必使用事務會話。

使用 DefaultMessageListenerContainer

在大多數情況下使用此訊息監聽器容器。與 SimpleMessageListenerContainer 不同,此容器變體允許動態適應執行時需求,並且能夠參與外部管理的事務。配置 JtaTransactionManager 後,每條接收到的訊息都將註冊到 XA 事務中。因此,處理可以利用 XA 事務語義。此監聽器容器在對 JMS 提供者的低要求、高階功能(例如參與外部管理的事務)以及與 Jakarta EE 環境的相容性之間取得了良好的平衡。

您可以自定義容器的快取級別。請注意,當未啟用快取時,每次訊息接收都會建立一個新的連線和會話。將其與高負載的非持久訂閱結合使用可能會導致訊息丟失。在這種情況下,請務必使用適當的快取級別。

當代理宕機時,此容器還具有可恢復功能。預設情況下,一個簡單的 BackOff 實現每五秒重試一次。您可以指定自定義的 BackOff 實現以獲得更精細的恢復選項。有關示例,請參閱 ExponentialBackOff

像它的同級 (SimpleMessageListenerContainer) 一樣,DefaultMessageListenerContainer 支援原生 JMS 事務並允許自定義確認模式。如果對您的場景可行,強烈建議使用原生 JMS 事務而不是外部管理的事務——也就是說,如果您可以接受在 JVM 死亡時偶爾出現重複訊息的情況。您的業務邏輯中的自定義重複訊息檢測步驟可以涵蓋這種情況——例如,以業務實體存在檢查或協議表檢查的形式。任何此類安排都比替代方案效率高得多:使用 XA 事務(透過使用 JtaTransactionManager 配置 DefaultMessageListenerContainer)包裝您的整個處理過程,以涵蓋 JMS 訊息的接收以及訊息監聽器中業務邏輯的執行(包括資料庫操作等)。
預設的 AUTO_ACKNOWLEDGE 模式不提供適當的可靠性保證。當監聽器執行失敗(因為提供者在監聽器呼叫後自動確認每條訊息,沒有異常傳播到提供者)或當監聽器容器關閉(您可以透過設定 acceptMessagesWhileStopping 標誌來配置此行為)時,訊息可能會丟失。在需要可靠性時(例如,用於可靠的佇列處理和持久主題訂閱),請務必使用事務會話。

事務管理

Spring 提供了一個 JmsTransactionManager,它管理單個 JMS ConnectionFactory 的事務。這使得 JMS 應用程式能夠利用 Spring 的託管事務功能,如資料訪問章節的事務管理部分所述。JmsTransactionManager 執行本地資源事務,將指定 ConnectionFactory 的 JMS 連線/會話對繫結到執行緒。JmsTemplate 自動檢測此類事務資源並相應地操作它們。

在 Jakarta EE 環境中,ConnectionFactory 對 Connection 和 Session 例項進行池化,因此這些資源在事務之間得到高效重用。在獨立環境中,使用 Spring 的 SingleConnectionFactory 會導致共享 JMS Connection,每個事務都有自己的獨立 Session。或者,考慮使用特定於提供者的池介面卡,例如 ActiveMQ 的 PooledConnectionFactory 類。

您還可以將 JmsTemplateJtaTransactionManager 和支援 XA 的 JMS ConnectionFactory 一起使用以執行分散式事務。請注意,這需要使用 JTA 事務管理器以及正確配置 XA 的 ConnectionFactory。(請查閱您的 Jakarta EE 伺服器或 JMS 提供者的文件。)

在使用 JMS API 從 Connection 建立 Session 時,在託管和非託管事務環境中重用程式碼可能會令人困惑。這是因為 JMS API 只有一個工廠方法來建立 Session,並且它需要事務和確認模式的值。在託管環境中,設定這些值是環境事務基礎設施的責任,因此這些值被供應商對 JMS Connection 的包裝器忽略。當您在非託管環境中使用 JmsTemplate 時,可以透過使用 sessionTransactedsessionAcknowledgeMode 屬性來指定這些值。當您將 PlatformTransactionManagerJmsTemplate 一起使用時,模板始終會獲得一個事務性 JMS Session

© . This site is unofficial and not affiliated with VMware.