本指南提供詳細資訊,幫助您透過 Java Message Service (JMS) 2.0 API 成功與 Azure 服務匯流排 溝通。
身為 Java 開發人員,如果您不熟悉 Azure 服務總線,請考慮閱讀下列文章。
| 入門指南 | 概念 |
|---|---|
Java 訊息服務(JMS)程式設計模型
Java 訊息服務 API 程式設計模型在以下章節中說明:
備註
Azure 服務總線進階層 支援 JMS 1.1 和 JMS 2.0。
Azure 服務總線 - 標準 層支援有限的 JMS 1.1 功能。 更多細節請參閱 此文件。
JMS - 建置組塊
請使用以下建構模組與 JMS 應用程式溝通。
連線中心
備註
函azure-servicebus-jms式庫有兩個版本: com.azure:azure-servicebus-jms (版本 2.0.0+)適用於 Jakarta EEjakarta.jms.*(),以及com.microsoft.azure:azure-servicebus-jms(版本 1.0.x)適用於 Java EE(javax.jms.*)。 關於如何選擇合適的產物,請參閱 Jakarta EE 與 javax 支援。
用戶端使用連線工廠物件連接至 JMS 提供者。 連線工廠封裝了一組由管理員定義的連線設定參數。
每個連線工廠都是 ConnectionFactory 介面、QueueConnectionFactory 介面或 TopicConnectionFactory 介面的一個實例。
為了簡化連接Azure 服務匯流排,這些介面分別透過 ServiceBusJmsConnectionFactory、ServiceBusJmsQueueConnectionFactory 或 ServiceBusJmsTopicConnectionFactory 實作。
這很重要
Java 應用程式使用 JMS 2.0 API,可以透過使用連接字串(連接字串)或利用 TokenCredential 來連接至 Azure 服務匯流排,從而使用 Microsoft Entra 支援的身份驗證。 使用 Microsoft Entra 驗證時,請視需要為該身分識別指派角色與權限。
在 Azure 上建立 系統指派的受控識別 ,並使用此身分識別來建立 TokenCredential。
TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build();
你可以用以下參數實例化連線工廠:
- 令牌認證 - 代表能夠提供 OAuth 令牌的認證。
- Host - Azure 服務匯流排 Premium 層命名空間的主機名稱。
- ServiceBusJmsConnectionFactorySettings 屬性集合,包含:
-
connectionIdleTimeoutMS- 閒置連線逾時(毫秒)。 -
traceFrames- 布林標誌,用於收集 AMQP 追蹤訊框以供除錯。 - 其他配置參數。
-
請依以下範例建立工廠。 令牌認證和主機是必要參數,但其他屬性是選擇性的。
String host = "<YourNamespaceName>.servicebus.windows.net";
ConnectionFactory factory = new ServiceBusJmsConnectionFactory(tokenCredential, host, null);
JMS 目的地
目的地是客戶端用來指定其產生的訊息目標以及其取用之訊息來源的物件。
目的地會對應至 Azure 服務匯流排中的實體 - 佇列 (在點對點傳送的使用情境下) 以及主題 (在發佈/訂閱的使用情境下)。
連接
連線會以 JMS 提供者封裝虛擬連線。 使用 Azure 服務匯流排,這代表了應用程式透過 AMQP 與 Azure 服務匯流排之間的具狀態連線。
從連接工廠建立連線,如下範例所示:
Connection connection = factory.createConnection();
會議
工作階段是用於產生及取用訊息的單一執行緒內容。 用它來創造訊息、訊息產生者和消費者。 它也提供交易性內容,使發送與接收可被組合為不可分割的工作單元。
從連接物件建立一個會話,如下範例所示:
Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
備註
JMS API 不支援從已啟用訊息工作階段的服務匯流排佇列或主題接收訊息。
會話模式
使用以下任一模式建立工作階段。
| 會話模式 | 行為 |
|---|---|
| Session.AUTO_ACKNOWLEDGE | 工作階段會在兩種情況下自動確認用戶端已收到訊息,其一是成功從接收呼叫返回時,其二是工作階段呼叫的訊息接聽程式成功處理並返回時。 |
| 會話.客戶端_確認 | 用戶端會藉由呼叫訊息的確認方法,來確認已取用的訊息。 |
| Session.DUPS_OK_ACKNOWLEDGE | 此確認模式會指示工作階段延遲確認訊息的傳遞。 |
| Session.SESSION_TRANSACTED | 將此值作為 Connection 物件中方法 createSession(int sessionMode) 的參數傳遞,指定該會話應該使用本地交易。 |
如果你沒指定會話模式,預設就是 Session.AUTO_ACKNOWLEDGE。
JMSContext
備註
JMSContext 定義為 JMS 2.0 規格的一部分。
JMSContext 結合了連接和會話物件所提供的功能。 你可以從連線工廠物件創建它。
JMSContext context = connectionFactory.createContext();
JMSCoNtext 模式
就像 Session 物件一樣,你可以用 Session 模式中提到的確認模式來建立 JMSContext。
JMSContext context = connectionFactory.createContext(JMSContext.AUTO_ACKNOWLEDGE);
如果你沒指定模式,預設就是 JMSContext.AUTO_ACKNOWLEDGE。
JMS 訊息產生者
訊息產生器是你透過使用 JMSContext 或 Session 所建立的物件。 用它來傳送訊息到目的地。
你可以將其建立為獨立物件,如下範例所示:
JMSProducer producer = context.createProducer();
或者你也可以在執行時建立它,當你需要發送訊息時。
context.createProducer().send(destination, message);
JMS 訊息取用者
訊息消費者是 JMSContext 或 Session 所建立的物件。 用它來接收發送到目的地的訊息。 請參照以下範例來創建:
JMSConsumer consumer = context.createConsumer(dest);
透過 receive() 方法同步接收
訊息取用者提供同步方式,透過 receive() 方法從目的地接收訊息。
如果未指定參數或逾時,或將逾時設為 0,則用戶端將無限期阻塞,直到訊息送達或連線中斷 (以較早發生者為準)。
Message m = consumer.receive();
Message m = consumer.receive(0);
當您提供非零的正值參數時,用戶端會阻塞直到計時器到期。
Message m = consumer.receive(1000); // time out after one second.
使用 JMS 訊息接聽程式進行異步接收
訊息監聽器是一種用於非同步處理目的地訊息的物件。 它會實作 MessageListener 介面,該介面包含 onMessage 方法,特定的商業邏輯必須存在於此方法中。
您必須先建立訊息接聽程式物件,並透過 setMessageListener 方法將其註冊至特定的訊息取用者。
Listener myListener = new Listener();
consumer.setMessageListener(myListener);
從主題取用
您可針對一個目的地建立 JMS Message Consumers,而該目的地可以是佇列或主題。
佇列上的消費者只是用戶端物件,存在於用戶端應用程式與 Azure 服務匯流排之間的工作階段 (及連線) 上下文中。
然而,主題的取用者由兩個部分組成 -
- 一個存在於會話(或 JMSContext)上下文中的 用戶端物件 ,以及
- 位於 Azure 服務匯流排上的訂用帳戶實體。
訂閱方式在此 說明,且 可為以下類型之一:
- 共用永久性訂閱
- 共用非永久性訂閱
- 非共用永久性訂閱
- 非共用非永久性訂閱
JMS 佇列瀏覽器
JMS API 提供一個 QueueBrowser 物件,應用程式可用來瀏覽佇列中的訊息並顯示每則訊息的標頭值。
你可以使用 JMSContext 建立佇列瀏覽器,如下範例所示:
QueueBrowser browser = context.createBrowser(queue);
備註
JMS API 不提供用來瀏覽主題的 API。
這個限制存在是因為主題本身並未儲存訊息。 一旦訊息傳送至主題,就會轉送至適當的訂用帳戶。
JMS 訊息選擇器
接收應用程式可以使用訊息選擇器來過濾他們收到的訊息。 透過使用訊息選擇器,接收端應用程式將過濾訊息的工作卸給 JMS 提供者(此處為 Azure 服務匯流排),而非自行承擔此責任。
你可以在建立以下任何消費者時使用選擇器:
- 共享持久訂閱
- 未共用的永久性訂用帳戶
- 共用的非永久性訂用帳戶
- 未共用的非永久性訂用帳戶
- 佇列取用者
- 佇列瀏覽器
備註
服務匯流排 選擇器不支援 LIKE 和 BETWEEN SQL 關鍵字。
排程訊息(傳送延遲)
JMS 2.0 支援透過在 setDeliveryDelay 或 MessageProducer 上使用 JMSProducer 方法來排程一則訊息,以供未來傳送。 設定此屬性後,服務匯流排 會接受訊息,但僅在延遲期過後才會讓消費者看到訊息。
MessageProducer producer = session.createProducer(queue);
// Schedule a message for delivery 30 seconds from now
producer.setDeliveryDelay(30000);
producer.send(session.createTextMessage("Scheduled message"));
完整工作範例請參見 azure-servicebus-jms-samples 倉庫中的 QueueScheduledSend.java。
連接工廠選擇與韌性
當您在 Spring Boot 或其他管理 JMS 連線的框架中使用 ServiceBusJmsConnectionFactory 時,請選擇正確的連線工廠包裝器,以確保 發送 和 監聽 的穩定運行。
建議的設定
| Role | 連線中心 | 原因為何 |
|---|---|---|
發送者 (JmsTemplate) |
CachingConnectionFactory 換行 ServiceBusJmsConnectionFactory |
JmsTemplate 預設每次發送時建立並關閉連線。
CachingConnectionFactory 維持單一 AMQP 連線並快取會話,避免連線流失,避免負載時耗盡代理資源。 |
聽眾 (@JmsListener, DefaultMessageListenerContainer) |
生食 ServiceBusJmsConnectionFactory (未包裝) |
每個監聽器容器擁有獨立生命週期的 AMQP 連線。 如果連線失敗(token到期、閘道升級、網路異常),只有該監聽器會受影響,Spring 會自動重建連線。 |
聽眾應避免的事項
警告
千萬不要將 SingleConnectionFactory 與監聽器容器搭配使用。 它強制所有聽眾共用同一個 JMS 連線。 如果該連線因任何原因中斷,所有聽眾會同時失去連線,無法獨立恢復。 使用原始 ServiceBusJmsConnectionFactory 檔案,讓每個監聽器容器都能管理自己的連線。
在接聽程式容器中使用 CachingConnectionFactory 也可能導致問題,因為快取的工作階段可能會參照到過期的底層連線。 對於接聽程式而言,原始工廠可確保每個容器都能獨立建立新的連線。
Spring Cloud Azure 預設設定
如果你使用 spring-cloud-azure-starter-servicebus-jms (版本 6.2.0+),啟動器預設會套用這個出廠分離:
spring.jms.servicebus.pool.enabled |
spring.jms.cache.enabled |
發送器工廠 | 監聽器工廠 |
|---|---|---|---|
| (未設定) | (未設定) | CachingConnectionFactory |
ServiceBusJmsConnectionFactory |
| (未設定) | true |
CachingConnectionFactory |
CachingConnectionFactory |
| (未設定) | false |
ServiceBusJmsConnectionFactory |
ServiceBusJmsConnectionFactory |
true |
(未設定) | JmsPoolConnectionFactory |
JmsPoolConnectionFactory |
在較舊版本(6.2.0 之前),發送端和監聽者預設使用 ServiceBusJmsConnectionFactory 連線,導致發送者每次傳送都建立新的連線。
新增例外監聽器
若沒有例外接聽程式,連線中斷將完全不會被通知。 在傳送者與接聽程式的工廠中新增 jakarta.jms.ExceptionListener 以提升可檢視性:
connection.setExceptionListener(exception -> {
log.error("JMS connection error: {}", exception.getMessage(), exception);
});
在 Spring Boot 中,將例外聆聽器設於 CachingConnectionFactory (用於發送者)和( DefaultJmsListenerContainerFactory 用於監聽器)。
欲完整示範所有這些模式,請參閱 azure-servicebus-jms-samples 倉庫中的 Spring Boot JMS Resilience 範例。
無效信件佇列
Azure 服務匯流排中的每個佇列與主題訂閱,都會對應一個無效信件佇列 (DLQ)。 系統會自動將無法傳送或處理的訊息移至 DLQ。 例如,當訊息超過最大送達次數或其存活時間(TTL)到期時,系統會將訊息移至DLQ。
這很重要
若要將 TTL 過期的訊息移至 DLQ,請為佇列或訂用帳戶啟用訊息到期無效信件。 若沒有此設定,系統會自動丟棄過期訊息。 如需設定步驟,請參閱為佇列或訂用帳戶啟用無效信件。
在 JMS 中,您可透過建構完整路徑並使用其建立 JmsQueue,將 DLQ 作為獨立目的地來存取。 不需要特殊的 API。
佇列 DLQ 路徑格式:
<queue-name>/$deadletterqueue
主題訂閱 DLQ 路徑格式:
<topic-name>/Subscriptions/<subscription-name>/$deadletterqueue
範例 - 從佇列的無效信件佇列取用:
import org.apache.qpid.jms.JmsQueue;
// Construct the DLQ path for a queue named "orders"
String dlqPath = "orders/$deadletterqueue";
JmsQueue dlqDestination = new JmsQueue(dlqPath);
// Create a consumer on the DLQ and receive messages
MessageConsumer dlqConsumer = session.createConsumer(dlqDestination);
Message message = dlqConsumer.receive(5000);
無效信件訊息包含用於描述該訊息被轉為無效信件原因的中繼資料屬性:
| 房產 | Description |
|---|---|
DeadLetterReason |
訊息為死字母的原因(例如, TTLExpiredException 或 MaxDeliveryCountExceeded)。 |
DeadLetterErrorDescription |
無效信件原因的人類可讀描述。 |
請使用以下 message.getStringProperty()方法讀取這些性質:
String reason = message.getStringProperty("DeadLetterReason");
String description = message.getStringProperty("DeadLetterErrorDescription");
完整工作範例請參見 azure-servicebus-jms-samples 倉庫中的 QueueDeadLetterReceive.java。
AMQP 配置和服務匯流排作業對應
以下是 AMQP 配置轉譯為服務匯流排作業的方式:
ACCEPTED = 1; -> Complete()
REJECTED = 2; -> DeadLetter()
RELEASED = 3; (just unlock the message in service bus, will then get redelivered)
MODIFIED_FAILED = 4; -> Abandon() which increases delivery count
MODIFIED_FAILED_UNDELIVERABLE = 5; -> Defer()
總結
這份開發者指南展示了使用 Java 訊息服務(JMS)的 Java 用戶端應用程式如何連接到 Azure 服務匯流排。
後續步驟
欲了解更多關於 Azure 服務匯流排 及 Java 訊息服務(JMS)實體的詳細資訊,請參閱以下文章: