1. 程式人生 > >Java訊息機制

Java訊息機制

1、問: 什麼是 Java 訊息服務?
答: Java 訊息服務(Java Message Service,JMS) API 是一個用於訪問企業訊息傳遞系統的 API。是 Java 2 Platform, Enterprise(J2EE)的一部分。

2、目前流行的訊息傳送產品有哪些?

答:目前流行的有ActiveMQ、IBM WebSphere MQ、SonicMQ等。

3、什麼時候可以用到java訊息機制?

答:(1)異構系統整合,整合現有資源,提高資源的利用率;

       (2)非同步請求處理,減輕或消除系統瓶頸,提高使用者生產率和系統的整體可伸縮性;

       (3)元件解偶,增加系統的靈活性

4、訊息傳送的兩種模型
4.1釋出/訂閱模型
客戶端傳送訊息到一個名為主題(topic)的虛擬通道中,每個訂閱該主題的消費者都會接收到每條訊息的一個副本。
4.2點對點模型

客戶端通過佇列(queue)這個虛擬通道來同步和非同步傳送、接收訊息,傳送到佇列的訊息只能被一個接收者所接收,即使有多個消費者時也只能有一個消費者處理訊息

5、JMS包含哪些介面?

JMS API可以分為3個主要部分:公共API、點對點API和釋出/訂閱API。

在JMS1.1中,公共API可被用於向一個佇列或一個主題傳送訊息,或從其中接收訊息。點對點API專門用於使用佇列的訊息傳送,而釋出/訂閱API則專門用於使用主題的訊息傳送。

在JMS公共API內部,和傳送和接收JMS訊息有關的JMS API介面主要有7個:
l          ConnectionFactory
l          Destination
l          Connection
l          Session
l          Message
l          MessageProducer
l          MessageConsumer
在這些公共介面中,ConnectionFactory和Destination必須使用JNDI(遵照JMS規範要求)從提供者處獲得。其他介面則可以通過工廠方法在不同的API介面中建立。舉例來說,一旦有了一個ConnectionFactory,就可以建立一個 Connection。一旦有了一個Connection,就可以建立一個Session。而一旦有了一個Session,就可以建立一個 Message、MessageProducer和MessageConsumer。這7個主要的JMS公共API介面之間的關係如圖1-5所示。
在JMS中,是Session物件儲存著用於訊息傳送的事務性工作單元(transactional unit),而不是Connection物件。這和JDBC不同,JDBC中是Connection物件儲存事務性工作單元。這就意味著在使用JMS時,一個應用程式通常只會有一個Connection物件,但是它可以有一個Session物件池。
另外,還有和異常處理、訊息優先順序及訊息永續性有關的其他介面。

6、java訊息分為哪些部分?

訊息頭、訊息屬性、訊息自身;

7、訊息過濾

訊息訂閱者需要對訊息進行過濾,否則訂閱者就會接受到主題或佇列的每一條訊息,浪費了不必要的資源(CPU、記憶體等),而使用訊息過濾技術,能讓訂閱者只接受它需要的訊息。(訊息過濾對於佇列消費尤其重要,因為一個佇列消費者消費訊息後其他消費者就不再可用,此時如果不對訊息進行過濾處理,這條訊息就很可能被浪費掉)。
訊息選擇器使用訊息屬性和訊息頭作為條件表示式的傳送載體(訊息體不能作為訊息選擇器的參考物件)。
訊息選擇器由識別符號、常量和比較運算子組成:
例:
        建立一個訊息如下:
<span style="white-space:pre">	</span> TextMessage textMessage = Session.createTextMessage();
         textMessage.setText(“mytestMsg”);
         textMessage.setStringProperty(“city”,”hangzhou”);
         textMessage.setStringProperty(“company”,”mycompany”);

         這條訊息中設定的訊息屬性名“city”和“company”代表訊息選擇器的識別符號,”hangzhou”和”mycompany”代表常量

         在消費端建立一個選擇器:
         
<span style="white-space:pre">	</span> String selector = “city = 'hangzhou' AND company='mycompany'”;
         QueueReceiver qReceiver = qSession.createReceiver(testQ,selector);
         其中“=”和“AND”為比較運算子,其他常用比較運算子還有:
         算數比較運算子(=、>、<、<=、<>等)

         like運算子、BETWEEN運算子、IN運算子、IS NULL運算子等

8 、訊息傳送的可靠性
在訊息的傳送過程中由於網路、軟硬體故障等都會導致訊息的傳送失敗, jms 為保證訊息的傳送定義了 3 條法則:
( 1 )訊息自主性,訊息是自包含的自主性實體,當傳送端發出這條訊息後這條訊息就不再受傳送端的限制,它可以在多個程序間被多次傳送。
( 2 )儲存轉發,當訊息被標記位永續性訊息時,就由 jms 提供者利用 “ 儲存並轉發 ” 機制,將訊息儲存在可信的介質上,防止發生故障時仍然可以正常恢復
( 3 )訊息確認機制,伺服器確認已經從傳送端收到了訊息,消費者則從確認從伺服器接收了訊息,對訊息傳送過程的監控,保證了訊息的可靠傳送。 訊息確認的 3 種模式:

8.1 、 AUTO_ACKNOWLEDGE 

從訊息生產者角度:傳送訊息後就開始阻塞,直到從訊息伺服器收到回覆,期間如發生異常則認為訊息未被傳送   

從訊息伺服器角度:非持久訊息在接受到訊息後通知生產者,並將訊息存入記憶體,永續性訊息在接受道訊息後先存入磁碟,然後通知生產者   

從消費者角度:接受到訊息後就向伺服器傳送確認資訊,如果伺服器沒有收到確認,會重新發送   

8.2 、 CLIENT_ACKNOWLEDGE 

消費者可在處理完業務邏輯後在程式碼重顯示呼叫 message.acknowledge() 通知 jms 提供者已成功接收道訊息   

8.3 、 DUPS_ACKNOWLEDGE 
可將一條訊息向同一目的地傳送兩次以上  
 
這裡介紹兩個概念:
(1)持久化訊息:訊息持久化就是在傳送者將訊息傳送出去後,訊息中心首先將訊息儲存到本地資料檔案、記憶體資料庫或者遠端資料庫等,然後試圖將訊息傳送給接收 者,傳送成功則將訊息從儲存中刪除,失敗則繼續嘗試。訊息中心啟動以後首先要檢查制定的儲存位置,如果有未傳送成功的訊息,則需要把訊息傳送出去。通過在訊息頭設定來實現,如:
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);

(2)持久訂閱者和非持久訂閱者:非持久訂閱者是指某個訂閱者由於某種原因停止執行,那麼在停止執行期間釋出到該訂閱者所訂閱主題的訊息就會無法獲得,持久訂閱者則剛好相反,持久訂閱者會接收發送到訂閱主題的所有訊息,無論訂閱者是否正常執行,電子郵件就是類似的一個例子。

持久化訊息和持久訂閱者在伺服器和消費者端之間的訊息傳送保證機制比較類似,但在有一種情況下他們還是存在區別的,對持久訂閱者來說,當訊息伺服器向傳送者傳送確認訊息之後,併為當前未執行的持久訂閱者將訊息儲存到介質之間如果傳送故障,該訊息就會丟失,而持久化訊息則是先儲存訊息道介質,然後才向傳送者傳送確認訊息,所以不存在這個問題,因此嚴格來說持久化訊息的可靠性會更高。

9 、事務性訊息

jms 事務性保證了一組傳送的訊息或接收的訊息要麼全部成功要麼全部失敗,概念上和我們在java 中使用的jta 相似,但jms 事務是由jms 提供者來管理的,而不是jta 。

使用方法如下:

// 此處用true ,表示使用事務性訊息
Session session =connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
// 用來發送的3 個訊息
MessageProducer sender = session.createProducer(“queue/testQueue”);
try{
    TextMessage message1 = session.createTextMessage(“ 要傳送的訊息1”);
      sender.send(message);
    TextMessage message2 = session.createTextMessage(“ 要傳送的訊息2”);
      sender.send(message);
    TextMessage message3 = session.createTextMessage(“ 要傳送的訊息3”);
      sender.send(message);
        session.commit();
    }catch(Exception e){
        try{
          session.rollback();
       }catch(JMSException e){
       }
    }