1. JMS架構(gòu)
Java 消息服務(wù)(Java Message Service,簡稱JMS)是用于訪問企業(yè)消息系統(tǒng)的開發(fā)商中立的API。企業(yè)消息系統(tǒng)可以協(xié)助應(yīng)用軟件通過網(wǎng)絡(luò)進(jìn)行消息交互。JMS 在其中扮演的角色與JDBC 很相似,正如JDBC 提供了一套用于訪問各種不同關(guān)系數(shù)據(jù)庫的公共API,JMS 也提供了獨(dú)立于特定廠商的企業(yè)消息系統(tǒng)訪問方式。
使用JMS 的應(yīng)用程序被稱為JMS 客戶端,處理消息路由與傳遞的消息系統(tǒng)被稱為JMS Provider,而JMS 應(yīng)用則是由多個JMS 客戶端和一個JMS Provider 構(gòu)成的業(yè)務(wù)系統(tǒng)。發(fā)送消息的JMS 客戶端被稱為生產(chǎn)者(producer),而接收消息的JMS 客戶端則被稱為消費(fèi)者(consumer)。同一JMS 客戶端既可以是生產(chǎn)者也可以是消費(fèi)者。
JMS 的編程過程很簡單,概括為:應(yīng)用程序A 發(fā)送一條消息到消息服務(wù)器(也就是JMS Provider)的某個目得地(Destination),然后消息服務(wù)器把消息轉(zhuǎn)發(fā)給應(yīng)用程序B。因為應(yīng)用程序A 和應(yīng)用程序B 沒有直接的代碼關(guān)連,所以兩者實現(xiàn)了解偶。如下圖:
消息傳遞系統(tǒng)的中心就是消息。一條Message 由三個部分組成:
消息的組成
1. 頭(head)
每條JMS 消息都必須具有消息頭。頭字段包含用于路由和識別消息的值。可以通過多種方式來設(shè)置消息頭的值:
a. 由JMS 提供者在生成或傳送消息的過程中自動設(shè)置
b. 由生產(chǎn)者客戶機(jī)通過在創(chuàng)建消息生產(chǎn)者時指定的設(shè)置進(jìn)行設(shè)置
c. 由生產(chǎn)者客戶機(jī)逐一對各條消息進(jìn)行設(shè)置
2. 屬性(property)
消息可以包含稱作屬性的可選頭字段。他們是以屬性名和屬性值對的形式制定的??梢詫傩允菫橄㈩^得擴(kuò)展,其中可以包括如下信息:創(chuàng)建數(shù)據(jù)的進(jìn)程、數(shù)據(jù)的創(chuàng)建時間以及每條數(shù)據(jù)的結(jié)構(gòu)。JMS提供者也可以添加影響消息處理的屬性,如是否應(yīng)壓縮消息或如何在消息生命周期結(jié)束時廢棄消息。
3. 主體(body)
包含要發(fā)送給接收應(yīng)用程序的內(nèi)容。每個消息接口特定于它所支持的內(nèi)容類型。JMS為不同類型的內(nèi)容提供了他們各自的消息類型,但是所有消息都派生自Message接口。
StreamMessage 一種主體中包含Java基元值流的消息。其填充和讀取均按順序進(jìn)行。
MapMessage 一種主體中包含一組鍵--值對的消息。沒有定義條目順序。
TextMessage 一種主體中包含Java字符串的消息(例如,XML消息)。
ObjectMessage 一種主體中包含序列化Java對象的消息。
BytesMessage 一種主體中包含連續(xù)字節(jié)流的消息。
例如:MapMessage 消息格式
消息的傳遞模型
JMS支持兩種消息傳遞模型:點對點(point-to-point,簡稱PTP)和發(fā)布/訂閱(publish/subscribe,簡稱pub/sub)。這兩種消息傳遞模型非常相似,但有以下區(qū)別:
a. PTP消息傳遞模型規(guī)定了一條消息之恩能夠傳遞費(fèi)一個接收方。
b. Pub/sub消息傳遞模型允許一條消息傳遞給多個接收方
每個模型都通過擴(kuò)展公用基類來實現(xiàn)。例如:javax.jms.Queue和Javax.jms.Topic都擴(kuò)展自javax.jms.Destination類。
1. 點對點消息傳遞
通過點對點的消息傳遞模型,一個應(yīng)用程序可以向另外一個應(yīng)用程序發(fā)送消息。在此傳遞模型中,目標(biāo)類型時隊列。消息首先被傳送至隊列目標(biāo),然后從改對壘將消息傳送至對此隊列進(jìn)行監(jiān)聽的某個消費(fèi)者,如下圖:
一個隊列可以關(guān)聯(lián)多個隊列發(fā)送方和接收方,但一條消息僅傳遞給一個接收方。如果多個接收方正在監(jiān)聽隊列上的消息,JMS Provider將根據(jù)“先來者優(yōu)先”的原則確定由哪個價售房接受下一條消息。如果沒有接收方在監(jiān)聽隊列,消息將保留在隊列中,直至接收方連接到隊列為止。這種消息傳遞模型是傳統(tǒng)意義上的拉模型或輪詢模型。在此列模型中,消息不時自動推動給客戶端的,而是要由客戶端從隊列中請求獲得。
2. 發(fā)布/訂閱消息傳遞
通過發(fā)布/訂閱消息傳遞模型,應(yīng)用程序能夠?qū)⒁粭l消息發(fā)送到多個接收方。在此傳送模型中,目標(biāo)類型是主題。消息首先被傳送至主題目標(biāo),然后傳送至所有已訂閱此主題的或送消費(fèi)者。如下圖:
主題目標(biāo)也支持長期訂閱。長期訂閱表示消費(fèi)者已注冊了主題目標(biāo),但在消息到達(dá)目標(biāo)時改消費(fèi)者可以處于非活動狀態(tài)。當(dāng)消費(fèi)者再次處于活動狀態(tài)時,將會接收該消息。如果消費(fèi)者均沒有注冊某個主題目標(biāo),該主題只保留注冊了長期訂閱的非活動消費(fèi)者的消息。與PTP消息傳遞模型不同,pub/sub消息傳遞模型允許多個主題訂閱者接收同一條消息。JMS一直保留消息,直至所有主題訂閱者都接收到消息為止。pub/sub消息傳遞模型基本上時一個推模型。在該模型中,消息會自動廣播,消費(fèi)者無須通過主動請求或輪詢主題的方法來獲得新的消息。
上面兩種消息傳遞模型里,我們都需要定義消息生產(chǎn)者和消費(fèi)者,生產(chǎn)者吧消息發(fā)送到JMS Provider的某個目標(biāo)地址(Destination),消息從該目標(biāo)地址傳送至消費(fèi)者。消費(fèi)者可以同步或異步接收消息,一般而言,異步消息消費(fèi)者的執(zhí)行和伸縮性都優(yōu)于同步消息接收者,體現(xiàn)在:
1. 異步消息接收者創(chuàng)建的網(wǎng)絡(luò)流量比較小。單向?qū)|消息,并使之通過管道進(jìn)入消息監(jiān)聽器。管道操作支持將多條消息聚合為一個網(wǎng)絡(luò)調(diào)用。
2. 異步消息接收者使用線程比較少。異步消息接收者在不活動期間不使用線程。同步消息接收者在接收調(diào)用期間內(nèi)使用線程,結(jié)果線程可能會長時間保持空閑,尤其是如果該調(diào)用中指定了阻塞超時。
3.對于服務(wù)器上運(yùn)行的應(yīng)用程序代碼,使用異步消息接收者幾乎總是最佳選擇,尤其是通過消息驅(qū)動Bean。使用異步消息接收者可以防止應(yīng)用程序代碼在服務(wù)器上執(zhí)行阻塞操作。而阻塞操作會是服務(wù)器端線程空閑,甚至?xí)?dǎo)致死鎖。阻塞操作使用所有線程時則發(fā)生死鎖。如果沒有空余的線程可以處理阻塞操作自身解鎖所需的操作,這該操作永遠(yuǎn)無法停止阻塞。
2. JMS Provider(ActiveMQ)
特性及優(yōu)勢
1. 實現(xiàn)JMS1.1規(guī)范,支持J2EE1.4以上。
2. 可運(yùn)行與任何JVM和大部分web容器(ActiveMQ works great in any JVM)
3. 支持多種語言客戶端(java, C, C++, Ajax, ActionScript等等)
4. 支持多種協(xié)議(stomp, openwire, REST)
5. 良好的Spring支持(ActiveMQ has great Spring Support)
6. 速度很快,JBossMQ的十倍(ActiveMQ is very fast; often 10x faster than JBossMQ)
7. 與OpenJMS、JBossMQ等開源jms provider相比,ActiveMQ有apache的支持,持續(xù)發(fā)展的優(yōu)勢明顯
Queue與Topic的比較
1. JMS Queue執(zhí)行l(wèi)oad balancer語義
一條消息僅能被一個consumer收到。如果在message發(fā)送的時候沒有可用的consumer,那么它講被保存一直到能處理該message的consumer可用。如果一個consumer收到一條message后卻不響應(yīng)它,那么這條消息將被轉(zhuǎn)到另外一個consumer那兒。一個Queue可以有很多consumer,并且在多個可用的consumer中負(fù)載均衡。
2. Topic實現(xiàn)publish和subscribe語義
一條消息被publish時,他將發(fā)送給所有感興趣的訂閱者,所以零到多個subscriber將接收到消息的一個拷貝。但是在消息代理接收到消息時,只有激活訂閱的subscriber能夠獲得消息的一個拷貝。
3. 分別對應(yīng)兩種消息模式
Point-to-Point(點對點),Publisher/Subscriber Model(發(fā)布/訂閱者)
其中在Publicher/Subscriber模式下又有Nondurable subscription(非持久化訂閱)和durable subscription(持久化訂閱)兩種消息處理方式。
Point-to-Point(點對點)消息模式開發(fā)流程
1. 生產(chǎn)者(producer)開發(fā)流程
1.1 創(chuàng)建 Connection
1.2 創(chuàng)建Session
1.3 創(chuàng)建Destination對象
1.4 創(chuàng)建MessageProducer
1.5 發(fā)送消息到隊列(Queue)
2. 消費(fèi)者(consumer)開發(fā)流程
2.1 實現(xiàn)MessageListener接口
2.2 創(chuàng)建Connection
2.3 創(chuàng)建Session和Destination
2.4 創(chuàng)建replayProducer【可選】
2.5 創(chuàng)建MessageConsumer
2.6 消費(fèi)message
Publish/Subscriber(發(fā)布/訂閱者)消息開發(fā)模式
1. 訂閱者(Subscriber)開發(fā)流程
1.1 實現(xiàn)MessageListener接口
在onMessage()方法中監(jiān)聽發(fā)布者發(fā)出的消息隊列,并做相應(yīng)處理。
1.2 創(chuàng)建Connection
根據(jù)url, user和password創(chuàng)建一個jms connection
1.3 創(chuàng)建Session
在connection的基礎(chǔ)上創(chuàng)建一個session,同時設(shè)置是否支持和ACKNOWLEDGE標(biāo)志。
1.4 創(chuàng)建 Topic
創(chuàng)建兩個Topic,topictest.message用于接收發(fā)布者發(fā)出的消息,topictest.control用于向發(fā)布者發(fā)送消息,實現(xiàn)雙方的交互。
1.5 創(chuàng)建consumer和producer對象
根據(jù)topictest.message創(chuàng)建consumer,根據(jù)topictest.control創(chuàng)建producer
1.6 接收處理消息
在onMessage()方法中,對收到的消息進(jìn)行處理,可直接簡單在本地顯示消息,或者根據(jù)消息內(nèi)容不同處理對應(yīng)的業(yè)務(wù)邏輯(比如:數(shù)據(jù)庫更新、文件操作等等),并且可以使用 producer對象處理結(jié)果返回給發(fā)布者。
2. 發(fā)布者(Publisher)開發(fā)流程
2.1 實現(xiàn)MessageListener接口
在onMessage()方法中接收訂閱者的反饋消息。
2.2 創(chuàng)建Connection
根據(jù)url, user和password 創(chuàng)建一個 jms Connection。
2.3 創(chuàng)建session
在connection的基礎(chǔ)上創(chuàng)建一個session,同時設(shè)置是否支持事務(wù)和ACKNOWLEDGE標(biāo)志。
2.4 創(chuàng)建Topic
創(chuàng)建兩個Topic,topictest.messages用于向訂閱者發(fā)布消息,topictest.control用于接收訂閱者反饋的消息。這兩個Topic與訂閱者開發(fā)流程中的topic是一一對應(yīng)的。
2.5 創(chuàng)建consumer和producer對象
根據(jù)topictest.message創(chuàng)建publisher;
根據(jù)topictest.control穿件consumer,同時監(jiān)聽訂閱者反饋的消息。
3. JMS For Spring
Spring提供了用于簡化JMS API使用的抽象框架,并且對用戶屏蔽了JMS API中1.0.2和1.1版本的差異。
JMS的功能大致上分為兩塊,叫做消息制造和消息消耗。JmsTemplate用于制造消息和同步消息接收。和J2EE的事件驅(qū)動Bean風(fēng)格類似,對于異步接收消息,Spring提供了一些消息監(jiān)聽容器來創(chuàng)建消息驅(qū)動的POJO(MDP)。
1. Spring 配置 connectionFactory
2. Spring JmsTemplate
3. 發(fā)送的接收消息
說明(基于ActiveMQ5.4.2版本):
1、Web Console 的安全配置可參考
將conf/jetty.xml下面一段xml配置:
authenticate值設(shè)置為true即可!那用戶名/密碼的配置是在conf/jetty-realm.properties!
詳細(xì)可參考http://activemq.apache.org/web-console.html
2、連接安全配置可參考
將conf/activemq-security.xml中如下的配置
copy至conf/activemq.xml中
的下面(這是簡單的用戶名、密碼的認(rèn)證方式)!
用戶名、密碼的可在conf/credentials.properties配置!
詳細(xì)可參考: