java message service是java ee的規範之一,可以用來發送異步消息,在某些場景下,可以作為不同系統,或者不同子產品之間的內建方式。可以類比為通過資料庫來內建的方式,子產品a完成邏輯以後,往資料庫插入一條記錄,子產品b定時輪詢資料庫,如果查到相應的記錄,就進行處理。jms內建實際上思路是差不多的功能更強,并且提供了标準的api支援,而且也可以避免反複輪詢資料庫或者讀取檔案的i/o操作,對系統的整體性能可能會有提升。
有兩個明顯的優點。首先可使2個系統或子產品實作松耦合,子產品a不需要直接調用子產品b,隻需要往jms provider上發送一條約定格式的消息,子產品b收到這條消息,進行後續的業務處理。其次jms方式是異步的,意味着子產品a發送消息之後,不需要等待子產品b或者jms provider的響應,自身的業務邏輯可以繼續。
jms技術對應的規範是jsr914,規範的實作稱為jms provider,常見的實作有activemq、jboss mq、ibm websphere mq等。本文以activemq舉例。
一、activemq使用
activemq(其他jms provider也差不多)安裝之後,目錄結構是這樣的

運作bin目錄下的activemq.bat,會根據預設配置啟動一個broker。各種jms實作都有broker的概念。
啟動之後會占用至少2個端口,預設的是61616和8161。61616是等待jms client的連接配接,8161是activemq自帶的一個web應用。
http://localhost:8161/demo可看到各種官方提供的例子
http://localhost:8161/admin是activemq的管理控制台。這裡可以對隊列進行各種操作,如發送消息,檢視消息,清空隊列等。
activemq即使在不程式設計的情況下也可以通過這種方式來使用,如用websphere mq有時也不程式設計,直接通過websphere mq在兩地進行消息傳輸。當然大部分情況還是需要針對jms client進行程式設計的。
二、jms基本概念
前面說過jms的實作,稱為jms provider,可認為是jms的伺服器。jms的用戶端需要開發人員自行開發,稱為jms client 。
jms的消息機制有2種模型,一種是point to point,表現為隊列的形式,發送的消息隻能被一個接收者取走。另一種是topic,可被多個訂閱者訂閱,類似于群發。
connectionfactory用于jms client擷取與jms provider的連接配接。不同的jms産品對這個接口有不同的實作,如說activemq的該接口的實作類是activemqconnectionfactory。
connection由connectionfactory産生的,表示jms client與jms provider的連接配接。
session由connection産生的,表示一個會話。session是關鍵元件,message、producer/consumer、destination都是在session上建立的。
message傳輸的消息,包括head、properties、body,其中head必選。
destination消息源,對發送者來說就是消息發到哪裡,對接收者來說就是從哪裡取消息。destination有2個子接口,queue和topic,分别對應上面提到的2種模型。
message producer消息發送者,可注意到這裡需要把destination作為參數,傳入createproducer()方法,說明消息發送者是綁定到destination上的,這個發送者發送的消息會發送到這個綁定的destination上。
// 消息目的地
destination dest = session.createqueue("dotaqueue");
// 消息發送者
messageproducer producer = session.createproducer(dest);
message consumer消息接收者,和message producer是相反的一種元件。
三、代碼執行個體
這裡基于activemq進行開發,是以需要導入activemq提供的jar包。不過開發時應該盡量針對jms接口進行開發,不依賴特定的實作。例子是用main函數跑的,沒有在java ee容器裡跑,是以沒有辦法依賴jndi拿到connectionfactory的執行個體,隻能手工建立activemqconnectionfactory,是以和activemq的實作耦合了,沒有辦法連到别的jms實作上。如果實際的代碼用jndi或者spring來擷取connectionfactory的執行個體的話,那就可以僅針對接口程式設計,連接配接到任意jms
provider了。為了簡單起見例子也沒有用到spring,實際上spring對jms client提供了很好的支援。本例開發環境隻要導入activemq-all-5.6.0.jar,裡面已經包括了jms api、activemq-core、javaee-management api等必須的class。
message producer
public class main {
public static void main(string[] args) throws jmsexception {
string jmsprovideraddress = "tcp://localhost:61616";// 位址
connectionfactory connectionfactory = new activemqconnectionfactory(jmsprovideraddress);// 連接配接器
connection connection = connectionfactory.createconnection();// 建立連接配接
session session = connection.createsession(false,session.auto_acknowledge);// 打開會話
destination dest = session.createqueue("demoqueue");// 消息目的地
messageproducer producer = session.createproducer(dest);// 消息發送者
message message = session.createtextmessage("hello world");// 消息
producer.send(message);// 發送
producer.close();// 關閉
session.close();
connection.close();
}
}
代碼很簡單,可以參考上面的圖,各元件的關系比較清楚。
message consumer
public static void main(string[] args) throws jmsexception {
string jmsprovideraddress = "tcp://localhost:61616";// 位址
connectionfactory connectionfactory = new activemqconnectionfactory(jmsprovideraddress);// 連接配接器
connection connection = connectionfactory.createconnection();// 建立連接配接
session session = connection.createsession(false,session.auto_acknowledge);// 打開會話
string destinationname = "demoqueue";
destination dest = session.createqueue(destinationname);// 消息來源地
messageconsumer consumer = session.createconsumer(dest);
connection.start();
message message = consumer.receive();
textmessage textmessage = (textmessage) message;
string text = textmessage.gettext();
system.out.println("從activemq取回一條消息: " + text);
consumer.close();
connection.close();
和messageproducer的代碼基本類似,實際中一般會實作javax.jms.messagelistener接口,這樣就不需要手工調用receive()方法。
原帖位址:http://www.iteye.com/topic/1125922