1. 什么是JMS
JMS即Java消息服務(wù)(Java Message Service)應(yīng)用程序接口,是一個(gè)Java平臺(tái)中關(guān)于面向消息中間件(MOM)的API徘钥,用于在兩個(gè)應(yīng)用程序之間衔蹲,或分布式系統(tǒng)中發(fā)送消息,進(jìn)行異步通信呈础。Java消息服務(wù)是一個(gè)與具體平臺(tái)無(wú)關(guān)的API舆驶,絕大多數(shù)MOM提供商都對(duì)JMS提供支持(百度百科給出的概述)。我們可以簡(jiǎn)單的理解:兩個(gè)應(yīng)用程序之間需要進(jìn)行通信而钞,我們使用一個(gè)JMS服務(wù)沙廉,進(jìn)行中間的轉(zhuǎn)發(fā),通過(guò)JMS 的使用臼节,我們可以解除兩個(gè)程序之間的耦合撬陵。
2. JMS的優(yōu)勢(shì)
- Asynchronous(異步)
JMS is asynchronous by default. So to receive a message, the client is not required to send the request. The message will arrive automatically to the client as they become available.(JMS 原本就是一個(gè)異步的消息服務(wù),客戶端獲取消息的時(shí)候网缝,不需要主動(dòng)發(fā)送請(qǐng)求巨税,消息會(huì)自動(dòng)發(fā)送給可用的客戶端)
- Reliable(可靠)
JMS provides the facility of assurance that the message will delivered once and only once. You know that duplicate messages create problems. JMS helps you avoiding such problems.(JMS保證消息只會(huì)遞送一次。大家都遇到過(guò)重復(fù)創(chuàng)建消息問(wèn)題粉臊,而JMS能幫你避免該問(wèn)題草添。)
3. JMS的消息模型
JMS具有兩種通信模式:
- Point-to-Point Messaging Domain (點(diǎn)對(duì)點(diǎn))
- Publish/Subscribe Messaging Domain (發(fā)布/訂閱模式)
在JMS API出現(xiàn)之前,大部分產(chǎn)品使用“點(diǎn)對(duì)點(diǎn)”和“發(fā)布/訂閱”中的任一方式來(lái)進(jìn)行消息通訊扼仲。JMS定義了這兩種消息發(fā)送模型的規(guī)范远寸,它們相互獨(dú)立。任何JMS的提供者可以實(shí)現(xiàn)其中的一種或兩種模型屠凶,這是它們自己的選擇驰后。JMS規(guī)范提供了通用接口保證我們基于JMS API編寫(xiě)的程序適用于任何一種模型。
3.1 Point-to-Point Messaging Domain(點(diǎn)對(duì)點(diǎn)通信模型)
模式圖
涉及到的概念
在點(diǎn)對(duì)點(diǎn)通信模式中矗愧,應(yīng)用程序由消息隊(duì)列灶芝,發(fā)送方,接收方組成。每個(gè)消息都被發(fā)送到一個(gè)特定的隊(duì)列监署,接收者從隊(duì)列中獲取消息颤专。隊(duì)列保留著消息,直到他們被消費(fèi)或超時(shí)钠乏。
特點(diǎn)
- 每個(gè)消息只要一個(gè)消費(fèi)者
- 發(fā)送者和接收者在時(shí)間上是沒(méi)有時(shí)間的約束栖秕,也就是說(shuō)發(fā)送者在發(fā)送完消息之后恨闪,不管接收者有沒(méi)有接受消息譬正,都不會(huì)影響發(fā)送方發(fā)送消息到消息隊(duì)列中。
- 發(fā)送方不管是否在發(fā)送消息杜漠,接收方都可以從消息隊(duì)列中去到消息(The receiver can fetch message whether it is running or not when the sender sends the message)
- 接收方在接收完消息之后俏拱,需要向消息隊(duì)列應(yīng)答成功
3.2 Publish/Subscribe Messaging Domain(發(fā)布/訂閱通信模型)
模式圖
涉及到的概念
在發(fā)布/訂閱消息模型中暑塑,發(fā)布者發(fā)布一個(gè)消息,該消息通過(guò)topic傳遞給所有的客戶端锅必。該模式下事格,發(fā)布者與訂閱者都是匿名的,即發(fā)布者與訂閱者都不知道對(duì)方是誰(shuí)搞隐。并且可以動(dòng)態(tài)的發(fā)布與訂閱Topic驹愚。Topic主要用于保存和傳遞消息,且會(huì)一直保存消息直到消息被傳遞給客戶端劣纲。
特點(diǎn)
- 一個(gè)消息可以傳遞個(gè)多個(gè)訂閱者(即:一個(gè)消息可以有多個(gè)接受方)
- 發(fā)布者與訂閱者具有時(shí)間約束逢捺,針對(duì)某個(gè)主題(Topic)的訂閱者,它必須創(chuàng)建一個(gè)訂閱者之后癞季,才能消費(fèi)發(fā)布者的消息劫瞳,而且為了消費(fèi)消息,訂閱者必須保持運(yùn)行的狀態(tài)绷柒。
- 為了緩和這樣嚴(yán)格的時(shí)間相關(guān)性志于,JMS允許訂閱者創(chuàng)建一個(gè)可持久化的訂閱。這樣废睦,即使訂閱者沒(méi)有被激活(運(yùn)行)伺绽,它也能接收到發(fā)布者的消息。
4. JMS接收消息
在JMS中郊楣,消息的產(chǎn)生和消息是異步的憔恳。對(duì)于消費(fèi)來(lái)說(shuō)瓤荔,JMS的消息者可以通過(guò)兩種方式來(lái)消費(fèi)消息净蚤。
- 同步(Synchronous)
在同步消費(fèi)信息模式模式中,訂閱者/接收方通過(guò)調(diào)用 receive()方法來(lái)接收消息输硝。在receive()方法中今瀑,線程會(huì)阻塞直到消息到達(dá)或者到指定時(shí)間后消息仍未到達(dá)。 - 異步(Asynchronous)
使用異步方式接收消息的話,消息訂閱者需注冊(cè)一個(gè)消息監(jiān)聽(tīng)者橘荠,類似于事件監(jiān)聽(tīng)器屿附,只要消息到達(dá),JMS服務(wù)提供者會(huì)通過(guò)調(diào)用監(jiān)聽(tīng)器的onMessage()遞送消息哥童。
5. JMS編程模型
- 管理對(duì)象(Administered objects)-連接工廠(Connection -
Factories)和目的地(Destination) - 連接對(duì)象(Connections)
- 會(huì)話(Sessions)
- 消息生產(chǎn)者(Message Producers)
- 消息消費(fèi)者(Message Consumers)
- 消息監(jiān)聽(tīng)者(Message Listeners)
1.Connection Factories
創(chuàng)建Connection對(duì)象的工廠挺份,針對(duì)兩種不同的jms消息模型,分別有QueueConnectionFactory和TopicConnectionFactory兩種贮懈≡炔矗可以通過(guò)JNDI來(lái)查找ConnectionFactory對(duì)象《淠悖客戶端使用一個(gè)連接工廠對(duì)象連接到JMS服務(wù)提供者各聘,它創(chuàng)建了JMS服務(wù)提供者和客戶端之間的連接。JMS客戶端(如發(fā)送者或接受者)會(huì)在JNDI名字空間中搜索并獲取該連接抡医。使用該連接躲因,客戶端能夠與目的地通訊,往隊(duì)列或話題發(fā)送/接收消息忌傻。
QueueConnectionFactory queueConnFactory = (QueueConnectionFactory) initialCtx.lookup ("primaryQCF");
Queue purchaseQueue = (Queue) initialCtx.lookup ("Purchase_Queue");
Queue returnQueue = (Queue) initialCtx.lookup ("Return_Queue");
2.Destination
目的地指明消息被發(fā)送的目的地以及客戶端接收消息的來(lái)源大脉。JMS使用兩種目的地,隊(duì)列和話題芯勘。如下代碼指定了一個(gè)隊(duì)列和話題:
創(chuàng)建一個(gè)隊(duì)列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)建一個(gè)Topic 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);
3.Connection
Connection表示在客戶端和JMS系統(tǒng)之間建立的鏈接(對(duì)TCP/IP socket的包裝)箱靴。Connection可以產(chǎn)生一個(gè)或多個(gè)Session。跟ConnectionFactory一樣荷愕,Connection也有兩種類型:QueueConnection和TopicConnection衡怀。
連接對(duì)象封裝了與JMS提供者之間的虛擬連接,如果我們有一個(gè)ConnectionFactory對(duì)象安疗,可以使用它來(lái)創(chuàng)建一個(gè)連接抛杨。
Connection connection = connectionFactory.createConnection();
4.Session
Session 是我們對(duì)消息進(jìn)行操作的接口,可以通過(guò)session創(chuàng)建生產(chǎn)者荐类、消費(fèi)者怖现、消息等。Session 提供了事務(wù)的功能玉罐,如果需要使用session發(fā)送/接收多個(gè)消息時(shí)屈嗤,可以將這些發(fā)送/接收動(dòng)作放到一個(gè)事務(wù)中。
我們可以在連接創(chuàng)建完成之后創(chuàng)建session:
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
這里面提供了參數(shù)兩個(gè)參數(shù)吊输,第一個(gè)參數(shù)是是否支持事務(wù)饶号,第二個(gè)是事務(wù)的類型
5.Producter
消息生產(chǎn)者由Session創(chuàng)建,用于往目的地發(fā)送消息季蚂。生產(chǎn)者實(shí)現(xiàn)MessageProducer接口茫船,我們可以為目的地琅束、隊(duì)列或話題創(chuàng)建生產(chǎn)者;
MessageProducer producer = session.createProducer(dest);
MessageProducer producer = session.createProducer(queue);
MessageProducer producer = session.createProducer(topic);
6.Consumer
消息消費(fèi)者由Session創(chuàng)建算谈,用于接收被發(fā)送到Destination的消息涩禀。
MessageConsumer consumer = session.createConsumer(dest);
MessageConsumer consumer = session.createConsumer(queue);
MessageConsumer consumer = session.createConsumer(topic);
7.MessageListener
消息監(jiān)聽(tīng)器。如果注冊(cè)了消息監(jiān)聽(tīng)器然眼,一旦消息到達(dá)艾船,將自動(dòng)調(diào)用監(jiān)聽(tīng)器的onMessage方法。EJB中的MDB(Message-Driven Bean)就是一種MessageListener高每。