JMS簡介

什么是JMS

Java消息服務(Java Message Service,簡稱JMS)是用于訪問企業(yè)消息系統(tǒng)的開發(fā)商中立的API。企業(yè)消息系統(tǒng)可以協(xié)助應用軟件通過網(wǎng)絡進行消息交互。JMS在其中扮演的角色與JDBC很相似,正如JDBC提供了一套用于訪問各種不同關系數(shù)據(jù)庫的公共API,JMS也提供了獨立于特定廠商的企業(yè)消息系統(tǒng)訪問方式。

使用JMS的應用程序被稱為JMS客戶端,處理消息路由與傳遞的消息系統(tǒng)被稱為JMS Provider,而JMS應用則是由多個JMS客戶端和一個JMS Provider構成的業(yè)務系統(tǒng)。發(fā)送消息的JMS客戶端被稱為生產(chǎn)者(producer),而接收消息的JMS客戶端則被稱為消費者(consumer)。同一JMS客戶端既可以是生產(chǎn)者也可以是消費者。

JMS的編程過程很簡單,概括為:應用程序A發(fā)送一條消息到消息服務器(也就是JMS Provider)的某個目得地(Destination),然后消息服務器把消息轉發(fā)給應用程序B。因為應用程序A和應用程序B沒有直接的代碼關連,所以兩者實現(xiàn)了解耦。

消息的結構

1. 頭(head)

每條JMS 消息都必須具有消息頭。頭字段包含用于路由和識別消息的值。可以通過多種方式來設置消息頭的值:
a. 由JMS 提供者在生成或傳送消息的過程中自動設置
b. 由生產(chǎn)者客戶機通過在創(chuàng)建消息生產(chǎn)者時指定的設置進行設置
c. 由生產(chǎn)者客戶機逐一對各條消息進行設置

2. 屬性(property)

消息可以包含稱作屬性的可選頭字段。他們是以屬性名和屬性值對的形式制定的。可以將屬性是為消息頭得擴展,其中可以包括如下信息:創(chuàng)建數(shù)據(jù)的進程、數(shù)據(jù)的創(chuàng)建時間以及每條數(shù)據(jù)的結構。JMS提供者也可以添加影響消息處理的屬性,如是否應壓縮消息或如何在消息生命周期結束時廢棄消息。

3. 主體(body)

包含要發(fā)送給接收應用程序的內(nèi)容。每個消息接口特定于它所支持的內(nèi)容類型。JMS為不同類型的內(nèi)容提供了他們各自的消息類型,但是所有消息都派生自Message接口。
StreamMessage 一種主體中包含Java基元值流的消息。其填充和讀取均按順序進行。
MapMessage 一種主體中包含一組鍵--值對的消息。沒有定義條目順序。
TextMessage 一種主體中包含Java字符串的消息(例如,XML消息)。
ObjectMessage 一種主體中包含序列化Java對象的消息。
BytesMessage 一種主體中包含連續(xù)字節(jié)流的消息。
例如:MapMessage 消息格式

MapMessage={  
    Header={  
        ... standard headers ...  
        CorrelationID={123-00001}  
    }  
    Properties={  
        AccountID={Integer:1234}  
    }  
    Fields={  
        Name={String:Mark}  
        Age={Integer:47}  
    }   
} 

消息的傳遞模型

JMS支持兩種消息傳遞模型:點對點(point-to-point,簡稱PTP)和發(fā)布/訂閱(publish/subscribe,簡稱pub/sub)。這兩種消息傳遞模型非常相似,但有以下區(qū)別:
a. PTP消息傳遞模型規(guī)定了一條消息之恩能夠傳遞費一個接收方。
b. Pub/sub消息傳遞模型允許一條消息傳遞給多個接收方
每個模型都通過擴展公用基類來實現(xiàn)。例如:javax.jms.Queue和Javax.jms.Topic都擴展自javax.jms.Destination類。

1. 點對點消息傳遞

通過點對點的消息傳遞模型,一個應用程序可以向另外一個應用程序發(fā)送消息。在此傳遞模型中,目標類型時隊列。消息首先被傳送至隊列目標,然后從該隊列將消息傳送至對此隊列進行監(jiān)聽的某個消費者。
一個隊列可以關聯(lián)多個隊列發(fā)送方和接收方,但一條消息僅傳遞給一個接收方。如果多個接收方正在監(jiān)聽隊列上的消息,JMS Provider將根據(jù)“先來者優(yōu)先”的原則確定由哪個消費方接受下一條消息。如果沒有接收方在監(jiān)聽隊列,消息將保留在隊列中,直至接收方連接到隊列為止。這種消息傳遞模型是傳統(tǒng)意義上的拉模型或輪詢模型。在此列模型中,消息不是自動推動給客戶端的,而是要由客戶端從隊列中請求獲得。

2. 發(fā)布/訂閱消息傳遞

通過發(fā)布/訂閱消息傳遞模型,應用程序能夠將一條消息發(fā)送到多個接收方。在此傳送模型中,目標類型是主題。消息首先被傳送至主題目標,然后傳送至所有已訂閱此主題的或送消費者。

主題目標也支持長期訂閱。長期訂閱表示消費者已注冊了主題目標,但在消息到達目標時改消費者可以處于非活動狀態(tài)。當消費者再次處于活動狀態(tài)時,將會接收該消息。如果消費者均沒有注冊某個主題目標,該主題只保留注冊了長期訂閱的非活動消費者的消息。與PTP消息傳遞模型不同,pub/sub消息傳遞模型允許多個主題訂閱者接收同一條消息。JMS一直保留消息,直至所有主題訂閱者都接收到消息為止。pub/sub消息傳遞模型基本上時一個推模型。在該模型中,消息會自動廣播,消費者無須通過主動請求或輪詢主題的方法來獲得新的消息。

上面兩種消息傳遞模型里,我們都需要定義消息生產(chǎn)者和消費者,生產(chǎn)者吧消息發(fā)送到JMS Provider的某個目標地址(Destination),消息從該目標地址傳送至消費者。消費者可以同步或異步接收消息,一般而言,異步消息消費者的執(zhí)行和伸縮性都優(yōu)于同步消息接收者。

使用同步方式接收消息的話,消息訂閱者調(diào)用receive()方法。在receive()中,消息未到達或在到達指定時間之前,方法會阻塞,直到消息可用。
  使用異步方式接收消息的話,消息訂閱者需注冊一個消息監(jiān)聽者,類似于事件監(jiān)聽器,只要消息到達,JMS服務提供者會通過調(diào)用監(jiān)聽器的onMessage()遞送消息。

JMS接口

JMS應用程序由如下基本模塊組成:
1.管理對象(Administered objects)-連接工廠(Connection Factories)和目的地(Destination)
2.連接對象(Connections)
3.會話(Sessions)
4.消息生產(chǎn)者(Message Producers)
5.消息消費者(Message Consumers)
6.消息監(jiān)聽者(Message Listeners)

jms.png
  • JMS管理對象
    管理對象(Administered objects)是預先配置的JMS對象,由系統(tǒng)管理員為使用JMS的客戶端創(chuàng)建,主要有兩個被管理的對象:

  • 連接工廠(ConnectionFactory)和目的地(Destination)
    這兩個管理對象由JMS系統(tǒng)管理員通過使用Application Server管理控制臺創(chuàng)建,存儲在應用程序服務器的JNDI名字空間或JNDI注冊表。
    客戶端使用一個連接工廠對象連接到JMS服務提供者,它創(chuàng)建了JMS服務提供者和客戶端之間的連接。JMS客戶端(如發(fā)送者或接受者)會在JNDI名字空間中搜索并獲取該連接。使用該連接,客戶端能夠與目的地通訊,往隊列或話題發(fā)送/接收消息。讓我們用一個例子來理解如何發(fā)送消息:

QueueConnectionFactory queueConnFactory = (QueueConnectionFactory) initialCtx.lookup ("primaryQCF");
Queue purchaseQueue = (Queue) initialCtx.lookup ("Purchase_Queue");
Queue returnQueue = (Queue) initialCtx.lookup ("Return_Queue");

目的地指明消息被發(fā)送的目的地以及客戶端接收消息的來源。JMS使用兩種目的地,隊列和話題。如下代碼指定了一個隊列和話題。
創(chuàng)建一個隊列Session

QueueSession ses = con.createQueueSession (false, Session.AUTO_ACKNOWLEDGE);  //get the Queue object  
Queue t = (Queue) ctx.lookup ("myQueue");  //create QueueReceiver  
QueueReceiver receiver = ses.createReceiver(t); 

創(chuàng)建一個話題Session

TopicSession ses = con.createTopicSession (false, Session.AUTO_ACKNOWLEDGE); // get the Topic object  
Topic t = (Topic) ctx.lookup ("myTopic");  //create TopicSubscriber  
TopicSubscriber receiver = ses.createSubscriber(t);  
  • JMS連接
    連接對象封裝了與JMS提供者之間的虛擬連接,如果我們有一個ConnectionFactory對象,可以使用它來創(chuàng)建一個連接。
Connection connection = connectionFactory.createConnection();
創(chuàng)建完連接后,需要在程序使用結束后關閉它:
connection.close();
  • JMS 會話(Session)
    Session是一個單線程上下文,用于生產(chǎn)和消費消息,可以創(chuàng)建出消息生產(chǎn)者和消息消費者。
    Session對象實現(xiàn)了Session接口,在創(chuàng)建完連接后,我們可以使用它創(chuàng)建Session。
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
  • JMS消息生產(chǎn)者
    消息生產(chǎn)者由Session創(chuàng)建,用于往目的地發(fā)送消息。生產(chǎn)者實現(xiàn)MessageProducer接口,我們可以為目的地、隊列或話題創(chuàng)建生產(chǎn)者;
MessageProducer producer = session.createProducer(dest);
MessageProducer producer = session.createProducer(queue);
MessageProducer producer = session.createProducer(topic);
創(chuàng)建完消息生產(chǎn)者后,可以使用send方法發(fā)送消息:
producer.send(message);
  • JMS消息消費者
    消息消費者由Session創(chuàng)建,用于接受目的地發(fā)送的消息。消費者實現(xiàn)MessageConsumer接口,,我們可以為目的地、隊列或話題創(chuàng)建消費者;
MessageConsumer consumer = session.createConsumer(dest);
MessageConsumer consumer = session.createConsumer(queue);
MessageConsumer consumer = session.createConsumer(topic);
  • JMS消息監(jiān)聽器
    JMS消息監(jiān)聽器是消息的默認事件處理者,他實現(xiàn)了MessageListener接口,該接口包含一個onMessage方法,在該方法中需要定義消息達到后的具體動作。通過調(diào)用setMessageListener方法我們給指定消費者定義了消息監(jiān)聽器
Listener myListener = new Listener();
consumer.setMessageListener(myListener);
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,781評論 18 139
  • 什么是Java消息服務 Java消息服務指的是兩個應用程序之間進行異步通信的API,它為標準消息協(xié)議和消息服務提供...
    雨帶著眼淚滑落閱讀 967評論 1 4
  • 一、 消息隊列概述 消息隊列中間件是分布式系統(tǒng)中重要的組件,主要解決應用耦合、異步消息、流量削鋒等問題。實現(xiàn)高性能...
    步積閱讀 57,033評論 10 138
  • 1、前言 之前我們通過兩篇文章(架構設計:系統(tǒng)間通信(19)——MQ:消息協(xié)議(上)、架構設計:系統(tǒng)間通信(20)...
    境里婆娑閱讀 1,895評論 0 4
  • 1 消息隊列概述 消息隊列中間件是分布式系統(tǒng)中重要的組件,主要解決應用耦合,異步消息,流量削鋒等問題。實現(xiàn)高性能,...
    Bobby0322閱讀 10,895評論 0 24