閱讀463 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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


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

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

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

https://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();

        session.close();

        connection.close(); 
}  

和MessageProducer的代碼基本類似,實際中一般會實現javax.jms.MessageListener接口,這樣就不需要手工調用receive()方法。

原帖地址:https://www.iteye.com/topic/1125922

最後更新:2017-04-03 12:56:36

  上一篇:go 訊飛語音
  下一篇:go umount.nfs: /mydata: device is busy解決辦法