JBoss 系列八十四: 使用 JMS session 時的一個誤區

概述

我們通常使用 JMS session 連接JMS消息隊列,創建生產者往隊列發送消息,或創建消費者從隊列消費消息,BaseJMSTaskServer.java中的start()方法就是一個例子,注意BaseJMSTaskServer.java使用到JMS 相關的API如下:

import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSession;
import javax.jms.Session;

根據JMS標準的設計,這些 API 它是設計爲單個線程使用,我們必須在單個線程中創建使用並關閉它們。誤區是好多人在工作中忽略掉這點,創建 JMS session 後被多個線程併發使用,這種使用是錯誤的。我先摘出 JMS specifications 中相關定義如下,接這舉兩個典型的例子,以及如何避免誤區。

JMS specifications

JMS session objects are single threaded and can only be used by single thread that created them. An attempt to use them from another thread would result in an exception or some very strange errors.

典型例子一

jBPM 提供通過JMS的方式與Task Service交互(深入理解 jBPM Human Task - 使用JMS做傳輸媒介執行Human Task),JMSTaskClientConnector.java 用來供第三方程序使用,好多人設計JMSTaskClientConnector實例爲單例模式,多個線程中併發使用JMSTaskClientConnector,結果出現錯誤導致jBPM不能夠正常工作。

典型例子二

Spring 提供對JMS的封裝spring-jms,其中好多人對JmsTemplate使用也是有誤區的,常見的錯誤如下:

for(;;){
...
.getJmsExecuteTemplate().sendQueueString("XXXX");
...
}

這樣也導致併發使用JMS session現象發生,使得應用異常發生。

避免誤區

javax.jms.ServerSessionPool接口是爲JEE容器提供,JEE容器實現了該接口,該節口考慮的是併發多線程場景,例如部署消息驅動Bean到JEE容器就使用的是ServerSessionPool實現,它考慮到線程安全性等。
所以如何避免誤區很簡單,將你的併發請求交給JEE容器處理,或者自己實現javax.jms.ServerSessionPool,來完成線程安全等的考慮。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章