jms學習

      Java消息服務支持兩種消息模型:Point-to-Point消息(P2P;即:點對點)和發佈訂閱消息(Publish Subscribe messaging,簡稱Pub/Sub;即:廣播式)。JMS規範並不要求供應商同時支持這兩種消息模型,但開發者應該熟悉這兩種消息模型的優勢與缺點。


Clients A 和 B是消息生產者,以兩種不同的目的地向Clients C, D, 和E 發送消息:
1、 在clients A, C, 和 D之間的消息是點對點模式,使用這種模式,客戶端發送消息到隊列目的地,從這個隊列裏面只有一個消息接收者可以收到那個消息,其他訪問同一目的地的接收者不會接收到消息。
2、 在clients B, E, 和F之間的消息是發佈/訂閱模式。使用這種廣播模式,一個客戶端發送消息給主題目的地,任何數量的消費訂閱者可以從這個主題目的地來接收它們。
這兩種消息方式通常被稱爲消息域(messaging domains)。JMS提供這兩個消息域,因爲它們代表兩種常用的消息模式。當使用JMS API的時候,開發者能使用接口和方法來支持這兩種消息模式。當使用接口的時候,消息系統的行爲可能會有所不同,因爲,這兩種消息域有不同的語義,稍後會詳細介紹兩種消息域的語義。
P2P消息模型是在點對點之間傳遞消息時使用。如果應用程序開發者希望每一條消息都能夠被處理,那麼應該使用P2P消息模型。與Pub/Sub消息模型不同,P2P消息總是能夠被傳送到指定的位置。

Pub/Sub模型在一到多的消息廣播時使用。如果一定程度的消息傳遞的不可靠性可以被接受的話,那麼應用程序開發者也可以使用Pub/Sub消息模型。換句話說,它適用於所有的消息消費程序並不要求能夠收到所有的信息或者消息消費程序並不想接收到任何消息的情況。

發佈/訂閱
發佈/訂閱 (pub/sub) 消息傳遞系統支持事件驅動模型,在這種模型中,信息消費者和生產者參與消息的傳輸。生產者“發佈”事件,而消費者“訂閱”感興趣的事件並消費事件。生產者把消息把與特定主題關聯起來,然後消息傳遞系統根據消費者所註冊的感興趣主題,把消息路由給消費者。

點對點
在點對點消息傳遞系統中,消息是被路由到各個消費者的,該消費者維護“傳入”消息隊列。消息傳遞應用程序發送消息到指定隊列,然後客戶端從隊列中檢索消息。

JMS一般都不是用來整合一個系統,而是整合許多可能參與消息驅動環境的系統。JMS是一個用於開發和集成企業應用程序的重要的工具。因爲許多公司都有以前遺留下來的系統和新近開發的系統綜合起來的系統,消息的使用是整合整個企業的重要的步驟。

消息收發系統是異步的,也就是說,JMS 客戶機可以發送消息而不必等待迴應。

什麼是消息
消息是一個用於在組件和應用程序之間通訊的的方法。消息之間的傳遞是點對點的。任何終端之間都可以相互接受和發送消息。並且每個終端都必須遵守如下的規則
創建消息 -> 發送消息 -> 接收消息 -> 讀取消息

爲什麼要使用消息
理由很簡單,消息是一個分佈式的低耦合通訊方案。A發送一個消息到一個agent ,B作爲接受者去agent上獲取消息。但是A,B不需要同時到agent上去註冊。agent作爲一箇中轉爲A,B提供搞效率的通訊服務。

開發者的關注點
走到這裏,我也不想去解釋jms spec上那些抽象且複雜的概念了,說的很白,1年多了我自己也沒弄懂是個什麼東西,也沒時間從頭到尾去仔細的看,同時我認爲沒必要,我所關注的是如何讓jms跑起來,並且工作正常,所以spec只是個字典,當我需要用的時候纔去查。

開發者的jms環境
遵守簡單明瞭的原則,所謂jms環境只是2個對象
1> ConnectionFactory
2> Destination

JMS應用程序有四個組成部分:JMS服務提供者、消息管理對象、消息的生產者消費者和消息本身。

消息管理對象提供對消息進行操作的API。JMS API中有兩個消息管理對象:ConnectionFactory和Destination,根據消息的消費方式的不同ConnectionFactory可以分爲QueueConnectionFactory和TopicConnectionFactory,Destination可以分爲Queue和Topic。用這兩個管理對象可以建立到消息服務的會話。

消息的生產者和消費者。它們可以毫不相干,只需要消息的消費者知道如何使用消息即可。根據消息消費者數目的不同,消息的消費者分爲兩類:subscriber 和receiver,同樣消息發送者也分爲兩類:Publisher和Sender。

消息。JMS API規定了五種消息:Message、MapMessage、TextMessage、ByteMessage、StreamMessage和ObjectMessage

消費形式的不同造成JMS有兩組平行的API,這就是JMS的PTP(point to point)模型和PUB/SUB(publisher和subscriber、出版和訂閱)模型。PTP的消息應用中一個消息只有一個消費者,消費後該消息即不再有效。而PUB/SUB應用中一個消息可以有多個訂閱者,而且每個訂閱者不一定非要處理該消息。

相對於更加傳統的分佈式計算模型,消息傳遞系統提供了許多強大的優勢。首先,它們倡議在消息消費者和消息生產者之間進行“鬆散耦合”。在生產者和消費者之間存在着高級匿名:對於消息消費者,它不關心 誰 產生消息,在網絡上生產者在 哪裏,或者消息是 何時 產生的。


JMS應用中的消息發送
1、獲得一個上下文環境:
Context ctx = new InitialContext();
2、通過JNDI查找來建立一個ConnectionFactory對象:
ConnectionFactory cf = (ConnectionFactory) ctx.lookup("java:JmsXA");
3、通過JNDI查找來建立一個或多個Destination對象:
Destination dest = (Queue) ctx.lookup("queue/A");  
4、通過ConnectionFactory創建一個JMS Connection連接:
Connection conn = cf.createConnection();
5、創建一個或多個JMS Session對象:
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
6、使用一個Session對象和Destination對象,合作創建一個MessageProducer(消息發送端):
MessageProducer msgp = session.createProducer(dest);   //此處的dest已經被強制爲P2P Queue對象
QueueSender sender = (QueueSender) msgp; 
//此處發送端指明採用的是 PTP的方式來實現JMS。當然你也可以用Pub/Sub的方式來實現
Destination dest = (Topic) ctx.lookup("queue/A");  
...
TopicPublisher sender = (TopicPublisher) msgp;
7、通過某個Session建立一個或多個JMS Message對象:
//此處僅以文字消息發送爲例,您也可以建立和發送MapMessage, BytesMessage, ObjectMessage, StreamMessage
TextMessage msg = session.createTextMessage();
msg.setText("消息詳細內容");
8、在已有的連接上,開始發佈我們已經建立好的消息對象:
sender.send(msg);
9、關閉已經建立的連接:
conn.close();

JMS應用中的消息接收
1-5:同發送過程的初始化步驟1-5,因爲是消息的接收方,JNDI的尋址方式應該同於發送方,這裏的JNDI相當於是雙方接頭的暗號。
6、使用一個Session對象和Destination對象,合作創建一個MessageConsumer(消息接收端):
MessageConsumer msgconsumer = session.createConsumer(dest);
7、啓動這個已經建立的連接,準備接收來自發送方的消息:
conn.start();
8、截獲來自發送端的消息:
TextMessage msg = (TextMessage) msgconsumer.receive();
String message = msg.getText();
9、關閉已經建立的連接:
conn.close();

以上的消息接收端成功的接收了一條消息,如果我們要監控JMS消息的接收事件,需要在第7步之前,聲明一個實現了MessageListener接口的對象:
MessageListener ml = new JmsListenner();  
msgConsumer.setMessageListener(ml); 
這裏的JmsListenner是我們自定實現的一個MessageListener,其中關鍵的事件是:
public void onMessage(Message message);
一個Session對象可以同時控制旗下的多個Consumer對象和MessageListener對象,但是這個Session是一個單線程模式的傳遞機制,即:必須在當前Message對象被onMessage處理之後,才能繼續接收下一條異步傳送過來的Message對象


  JMS學習記錄 收藏
 
JMS (Java Message Service)是由SUN開發的一套API,它爲開發者提供一套訪問MOM(Message-Oriented Middleware:面向消息中間件)的標準方法。
JMS 分爲兩種消息域PTP(點對點)和Pub/Sub(發佈/訂閱)。PTP消息被產生者放入到一個隊列中,消費者則從小消息列隊中取走消息,消息一擔取走,消息就從隊列中移除。Pub/Sub消息和PTP最大的不同在於發佈者發佈一條消息後可以發送給所有訂閱者,所有訂閱者都擁有處理某一條消息的機會。(如圖1)
                                    (圖1)
                 發佈者A                   發佈者B
                        |                                 |
    --------MOM   消息中間件-----------------------
   |                 娛樂/音樂             it/管理              |
   ________________________________
               訂閱者A          訂閱者B     訂閱者C  (都能享受上面的服務,不用理會誰發佈的)
 JMS的一些重要接口
ConnectionFactory :創建一個受管理對象
Connection :連接到提供者的活動連接
Destination :一個封裝消息目標地址的受管理對象,如消息的來源地和發送滴,根據消息域的不同有兩個接口:Queue 和 Topic,前者對應PTP消息的目標地址,後者對應Pub/Sub消息的目標地址。
Session :發送和接受消息的單線程環境。(即一次會話)
MessageProducer:用於發送消息
MessageConsumer:用於接收消息
JMS高級接口與特定域接口(位於javax.jms包中)  
高級接口 PTP域子接口 PUB/SUB域子接口
ConnectionFactory QueueConnectionFactory TopicConnectionFactory
Connection QueueConnection TopicConnection
Destination QueueDestination TopicDestination
Session QueueSession TopicSession
MessageProducer QueueMessageProducer TopicMessageProducer
MessageConsumer QueueMessageConsumer TopicMessageConsumer


一個典型的JMS程序要經過以下步驟才能開始創建和使用消息
1、通過JNDI查詢ConnectionFactory
2、用ConnectionFactory創建一個Connection
3、用Connection創建一個或多個Session
4、通過JNDI查詢一個或多個Destination
5、用Session和Destination創建對應的MessageProducer和MessageConsumer
6、啓動Connection
JMS消息結構
 
JMS根據不同應用的用途定義了多種消息類型,由Message接口派生而來,一個Message由Header、Properties和Body三個部分組成。
 
Header是一組標準鍵值字段,客戶端和提供者都用它來標識和路由消息。
Properties用於彌補Header的不足,可以通過手工設置其他的屬性,Message提供了set<Type>Property(String name)和get<Type>Property()方式來讓開發者任意定義屬性。
Body消息正文,包括了發送給其他程序的消息內容,根據消息體內容的不同,JMS擁有5個消息類型,並分別通過Message的5個子接口來描述。
消息類型 說明
TextMessage 消息是一個字符
ObjectMessage 消息是一個實現了Serializable接口的對象
MapMessage 消息是一個MAP,包括一組鍵值對元素,鍵位一個字符,值爲任意對象
BytesMessage 消息是一個二進制數組
StreamMessage 消息是一組JAVA原始類型數據,這些數據通過標準流操作按順序進行填充和讀取

 
消息收發的機制:
JMS事務使用了Session對它進行操作,分別擁有支持事務語義的3個方法,通過這些方法啓動,提交和回滾一個事務,這些方法分別是begin()、commit()和rollback()。
 
消息確認是接收者在成功接收到消息後,將一個回執發送給MOM,告之已經成功接收到一種通知機制。確認方式有三種分別是:
1、 Session.AUTO_ACKNOWLEDGE:在完成接收消息時,Session自動發送一個確認回執。
2、 Session.CLIENT_ACKNOWLEDGE:由客戶端程序通過手工調用Message.acknowledge()方法顯示確認接收。
3、 Session.DUPS_OK_ACKNOWLEDGE:讓Session延遲發送確認回執。
例如:創建一個不需事務,自動確認的session方式
         Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
 
消息選擇是一種選擇機制,類似於SQL的查詢條件。
 
發送消息例子:
 
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.jms.Destination;
 
publicclass MessageSender {
   
    /**
     *發送方法
     */
    publicvoid send(String msgText){
      
       // 獲取jms連接
       Connection connection = null;
      
       try {
           // 獲取JNDI上下文
           InitialContext ctx = new InitialContext();
           ConnectionFactory cFactory = (ConnectionFactory)ctx.lookup("jndi/jmsConn");
          
           // 獲取Destination 目標地址
           Destination dest = (Destination)ctx.lookup("jndi/dest");
           ctx.close();
          
           // 獲取一個MOM的連接
           connection = cFactory.createConnection();
          
           // 創建JMS會話
           Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
          
           // 創建一個指定特定目標地址的消息發送者
           MessageProducer sender = session.createProducer(dest);
          
           // 建立Body內容
           TextMessage message = session.createTextMessage(msgText);
          
           // 發送給服務器
           sender.send(message);
          
       } catch (Exception e) {
           e.printStackTrace();
       } finally {
           try {
              connection.close();
           } catch (Exception e) {
              e.printStackTrace();
           }
       }
    }
}
 

 
接收消息例子:
 
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
 
publicclass MessageReceiver {
   
    /**
     *接收方法
     */
    publicvoid receive(){
       Connection connection = null;
      
       try {
           // 創建JNDI上下文
           InitialContext ctx = new InitialContext();
           ConnectionFactory cFactory = (ConnectionFactory)ctx.lookup("jndi/jmsConn");
          
           // 獲取目標地址信息
           Destination dest = (Destination)ctx.lookup("jndi/dest");
           ctx.close();
          
           // 獲取連接
           connection = cFactory.createConnection();
          
           // 獲取連接對話
           Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
          
           // 創建一個指向特定目標地址的消息消費者
           MessageConsumer receiver = session.createConsumer(dest);
          
           // 接收發送請求中的消息信息
           TextMessage textMsg = (TextMessage)receiver.receive();
          
           System.out.println("獲取內容:" + textMsg.getText());        
       } catch (Exception e) {
           e.printStackTrace();
       } finally {
           try {
              connection.close();
           } catch (JMSException e) {
              e.printStackTrace();

           }
       }
    }
}

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