天天看點

JMS(1)——基本執行個體

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也差不多)安裝之後,目錄結構是這樣的

JMS(1)——基本執行個體

運作bin目錄下的activemq.bat,會根據預設配置啟動一個broker。各種jms實作都有broker的概念。

啟動之後會占用至少2個端口,預設的是61616和8161。61616是等待jms client的連接配接,8161是activemq自帶的一個web應用。

http://localhost:8161/demo可看到各種官方提供的例子 

http://localhost:8161/admin是activemq的管理控制台。這裡可以對隊列進行各種操作,如發送消息,檢視消息,清空隊列等。 

JMS(1)——基本執行個體

activemq即使在不程式設計的情況下也可以通過這種方式來使用,如用websphere mq有時也不程式設計,直接通過websphere mq在兩地進行消息傳輸。當然大部分情況還是需要針對jms client進行程式設計的。

二、jms基本概念 

前面說過jms的實作,稱為jms provider,可認為是jms的伺服器。jms的用戶端需要開發人員自行開發,稱為jms client 。

jms的消息機制有2種模型,一種是point to point,表現為隊列的形式,發送的消息隻能被一個接收者取走。另一種是topic,可被多個訂閱者訂閱,類似于群發。

JMS(1)——基本執行個體

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。

JMS(1)——基本執行個體

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