一、消息傳送機制基礎
1、消息傳送機制的優點
①異構集成:在完全不同的平台上實現應用程序和系統請求調用服務。消息傳送機制提供跨應用程序和子系統共享數據和功能的去耦方案。
②緩解系統瓶頸:與一個同步組件處理眾多請求時,眾多請求一個接一個地積聚阻塞不同,這時候請求會發送到一個消息傳送系統,該系統將該請求分發給多個消息偵聽器組件(增加漏斗)。如此一來,就緩解了單獨采用點對點同步連接帶來的系統瓶頸。
③提高可伸縮性:通過引入能夠並發處理不同消息的多個消息接收者(消息偵聽器),消息傳送系統的可伸縮性得以實現。
④提高最終用戶生產率:通過使用異步消息傳送機制,用戶可以在向系統發出請求后,繼續做其他事情。
⑤ 體系結構靈活性和敏捷性:消息傳送機制抽象和去耦組件,能快速地響應軟硬件和業務的變化。使用消息傳送機制方式,消息生產者或是客戶端組件都不會知道接收 組件使用的是哪種編程語言或平台,組件或服務位於何處,組件或服務實現的名稱是什么,甚至用於訪問該組件或服務的是哪種協議。
2、企業消息傳送
消息是通過網絡從一個系統異步傳送給其他系統的。在異步消息傳送機制中,應用程序使用一個簡單的API來構建一條消息,然后再將該消息轉發給面向消息的中間件,以便傳送給一個或多個的預定接收者。一條消息就是一個業務數據包,它通過網絡從一個應用程序發送給其他應用程序。消息應該是自描述的,因為它包含所有必要的上下文,以便允許接收者獨立地完成它們的工作。
消息傳送系統由消息傳送客戶端和幾種消息傳送中間件服務器所組成。客戶端向消息傳送服務器發送消息,該服務器隨后再將那些消息分發給其他客戶端。客戶端是使用消息傳送API的一個業務應用程序或組件(JMS)。
① 集中式體系結構
依賴於一台消息服務器(也稱消息路由器或代理),它負責從一個消息傳送客戶端(JMS)向其他消息傳送客戶端(JMS)傳送信息,實現一個發送客戶端和其他接收客戶端之間的解耦。客戶端僅僅看到消息傳送服務器,而不會看到其他客戶端,這將允許在不會影響系統整體的情況下添加和刪除客戶端。通常,集中式體系結構使用的是星型的拓撲結構。
② 分布式體系結構
使用網絡層IP組播,沒有集中服務器,一些服務器功能(持久性、事務和安全性)作為一個客戶端的本地部分嵌入進來,而此時消息路由則利用IP組播協議委托給網絡層。
3、消息傳送模型
JMS支持兩類消息傳送模型(消息傳送域):點對點模型(P2P)和發布/訂閱(Pub/Sub)模型。點對點模型設計用於一對一消息傳送,發布/訂閱模型設計用於一對多消息廣播。
① 點對點模型:JMS客戶端通過隊列(queue)這個虛擬通道來同步和異步發送、接收消息,基於拉取(Pull)或者基於輪詢(Polling)的消息傳送模型,這種模型從隊列中請求消息,而不是自動地將消息推送給客戶端。耦合性比Pub/Sub模型更強。
② 發布/訂閱模型:消息會被發布到一個名為主題(topic)的虛擬通道中,基於推送(Push)的模型,消息自動地向消費者廣播,它們無須請求或輪詢主題來獲得新消息,每個訂閱者都會接受到發布者所發送的消息的一個副本。去耦能力比P2P模型更強。
4、JMS API
JMS本身並不是一種消息傳送系統,它是消息傳送客戶端和消息傳送系統通信時所需接口和類的一個抽象。JMS抽象可以訪問消息提供者。使用JMS,應用程序的消息傳送客戶端可以實現跨消息服務器產品的移植。
JMS API分為3個主要部分:公共API、點對點API和發布/訂閱API。公共API被用於向一個隊列或一個主題發送和接收消息,點對點API專門用於隊列,發布/訂閱API則專門用於主題。
在JMS公共API內部,和發送與接收JMS消息有關的JMS API接口主要有7個:ConnectionFactory、Destination、Connection、Session、Message、MessageProducer、MessageConsumer。
在這些公共接口中,ConnectionFactory、Destination必須使用JNDI從提供者處獲得。其他接口則可以通過工廠方法在不同的API接口中創建。
① 點對點API
向一個隊列發送和接收消息的接口:QueueConnectionFactory、Queue、QueueConnection、QueueSession、Message、QueueSender、QueueReceiver。
② 發布/訂閱API
內部接口:TopicConnectionFactory、Topic、TopicConnection、TopicSession、Message、TopicPublisher、TopicSubscriber。
5、RPC和異步消息傳送
①緊密耦合的RPC
緊密耦合的RPC模型最為成功的一個領域就是構建3層或n層應用程序。在這個模型中,表示層(第1層)使用RPC和中間層(第2層)的業務邏輯進行通信,訪問位於后端(第3層)的數據。
在調用一個遠程過程時,調用者將被阻塞,直到該過程完成並將控制權返回給調用者。從開發者的角度看,這種同步模型使得該系統就好像運行在一個進程當中。這些工作會依次完成,同時確保以預定順序完成。RPC同步的本質特性,將客戶端(進行調用的軟件)和服務器(為該調用服務的軟件)兩種緊密耦合在一起。導致出現相互高度依賴的系統,其中一個系統的失效會對其他系統產生立竿見影的影響。
②企業消息傳送
JMS提供一個松散耦合的環境,其中,系統組件的局部故障並不會妨礙系統的整體可用性。
JMS提供了保證傳送的方式,基於“保存並轉發”的機制,如果預定消費者當前不可用,底層消息服務器會將輸入的消息寫到一個持久存儲器中。隨后,當該應用程序變為可用時,“保存並轉發”機制會把這些消息都傳送給它們。
通過異步處理、“保存並轉發”以及“保證傳送”機制,JMS為保存業務應用程序連續運行並實現不間斷服務提供了很高的可用性。還通過Pub/Sub和P2P功能,提供了集成靈活性。通過位置透明和管理控制,提供了一種健壯的、基於服務的體系結構。
二、編寫一個簡單的示例
1、使用JMS發布/訂閱API來構建一個簡單的聊天應用程序。
2、解讀JNDI
JNDI是一個標准的Java擴展,它提供了一個統一的API,用於訪問多種目錄和命名服務。在JMS中,JNDI主要用於命名服務來定位受管對象。受管對象就是由系統管理員創建和配置的JMS對象。包括JMS ConnectionFactory和Destination對象,比如主題和隊列等。
受管對象和命名服務中的一個名稱相互綁定在一起。一個命名服務將名稱和分布式對象、文件和設施關聯起來,以便它們可以使用簡單的名稱而不是密碼似的網絡地址實現在網絡上的定位。
JNDI提供一個隱藏了命名服務細節的抽象,使得客戶端應用程序的可移植性更高。使用JNDI,JMS客戶端能夠瀏覽一個命名服務,並在不知道命名服務細節或它如何實現的情況下,引用受管對象。JNDI既是虛擬的,又是動態的。
一個InitialContext就是所有JNDI查找的起始點,它和文件系統根目錄的概念很相似。InitialContext提供了一個到目錄服務的網絡連接,這個目錄服務就發揮訪問JMS受管對象的根目錄作用。
InitialContext ctx = new InitialContext(); //使用jndi.properties文件獲得一個JNDI連接
3、TopicConnectionFactory
一旦實例化一個JNDI InitialContext對象,就可以使用它在消息傳送服務器的命名服務中查找TopicConnectionFactory。
TopicConnectionFactory用於創建到一個消息服務器的連接。一個TopicConnectionFactory就是一類受管對象,這就意味着它的屬性和行為要由負責消息傳送服務器的系統管理員來配置。
4、TopicConnection
TopicConnection表示和消息服務器的一個連接。從TopicConnectionFactory中創建的每個TopicConnection就是和該服務的唯一連接。
//查找一個JMS連接工廠並創建連接
TopicConnectionFactory conFactory =(TopicConnectionFactory)ctx.lookup(topicFactory);
TopicConnection connection = conFactory.createTopicConnection();
5、TopicSession
TopicSession對象是用於創建Message、TopicPublisher和TopicSubscriber對象的工廠。它還用作JMS內部的事務性工作單元。一個客戶端可以創建多個TopicSession對象,對發布者、訂閱者以及其相關事務提供粒度更細的控制。
//創建兩個JMS會話對象
TopicSession pubSession = connection.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);
TopicSession subSession = connection.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);
6、Topic
JNDI用於定位一個Topic對象,它是類似於TopicConnectionFactory的一個受管對象:Topic chatTopic =(Topic)ctx.lookup(topicName); //查找一個JMS主題
Topic對象是消息傳送服務器上一個實際主題的句柄或者標識符,該主題稱為物理主題。一個物理主題就是多個客戶端訂閱和發布消息的一條電子通道。
7、TopicPublisher
TopicPublisher用於將消息傳送給一個消息服務器上的特定主題。在createPublisher()方法中使用的Topic對象,確定了將從TopicPublisher接收消息。
TopicPublisher將消息異步傳送給該主題。異步傳送和消費消息是面向消息中間件的一個關鍵特性;TopicPublisher不會一直阻塞或等到所有訂閱者都接收到該消息為止,而是只要消息服務器一接收到消息,就會從publish()方法返回。
//創建一個JMS發布者和訂閱者。createSubscriber中附加的參數是一個消息選擇器(null)和noLocal標記的一個真值,它表明這個發布者生產的消息不應被它自己所消費。
TopicPublisher publisher = pubSession.createPublisher(chatTopic);
TopicSubscriber subscriber =subSession.createSubscriber(chatTopic,null,true);
8、TopicSubscriber
TopicSubscriber從特定的主題接收消息。消息服務器將這些消息異步推送給TopicSubscriber,TopicSubscriber不必輪詢消息服務器。
JMS中的發布/訂閱消息傳送模型包括了一個用於處理輸入消息的進程內Java事件模型。一個對象實現了偵聽器接口(MessageListener),然后使用TopicSubscriber進行注冊。一個TopicSubscriber只能有一個MessageListener對象。
當TopicSubscriber從它的主題接收一條消息時,調用了它的MessageListener對象的OnMessage()方法。
subscriber.setMessageListener(this); //設置一個JMS消息偵聽器
9、Message
TextMessage類用於封裝我們發送和接收的消息。TextMessage包含一個java.lang.String作為它的消息體。
消息類型之間的區別在很大程度上取決於它們的有效負載(即該消息包含的應用程序數據類型)。
10、會話與線程
JMS規范規定,一個會話不能同時在一個以上的的線程中運行。
三、深入剖析一條JMS消息
Message消息是整個JMS規范最為重要的部分。一個JMS應用程序中的所有數據和事件都是使用消息進行通信的,同時JMS其余部分也都在為消息傳輸服務。
一條JMS消息攜帶有應用程序數據,並能夠提供事件通知。對於分布式計算來說,它的作用是獨一無二的。在基於RPC的系統中,一條消息就是執行一個方法或者過程的一個命令,它將阻塞發送者知道一個應答已被接收為止。一個JMS消息並不是一個命令,它傳輸數據並告訴接收者有一些事情已經發生。一條消息並不指示接收者應該做什么,而且發送者也不會等待響應。這樣就實現了發送者和接收者的去耦,從而使得消息傳送系統和它們的消息比請求/應答范例的動態性和靈活性更強。
一個Message對象有3個部分:消息頭、消息屬性和消息數據自身(也稱有效負載或消息體)。消息具有不同的類型,這些類型由它們的有效負載所定義。
四、點對點消息傳送模型
1、P2P模型概覽
P2P模型的特性:消息通過隊列進行交換、每條消息僅會傳送給一個接收者、消息存在先后順序。
P2P模型會保證只有一個消費者來處理一條指定的消息。在消息要依次分別接收處理時,要在多個JMS客戶端之間均衡消息處理負載。
它提供的QueueBrower允許JMS客戶端對隊列進行快照,以查看正在等待被消費的消息。
P2P另一個用例是:在需要在組件之間進行同步通信,而那些組件卻是用不同的編程語言編寫的,或者是在不同的技術平台(如J2EE或.NET)上實現的。
使用基於消息的負載均衡,可以讓服務器端的組件實現更大的吞吐量,特別對於同構組件(即Java到Java)來所更是如此。
2、QBorrower和QLender應用程序
模擬一個基於P2P請求/應答模型的貸款申請場景
3、消息關聯
多個請求者同時發出請求,這就意味着發送者會向響應隊列發送多條消息(接收到的信息和發送的信息可以是不同類型),既然響應隊列可以包含多條消息,那么如何將接收的響應同原始消息相互關聯呢?最常用的消息關聯方法是將JMSCorrelationID消息頭屬性和JMSMessageID消息頭屬性結合在一起使用。
4、分析一個隊列
QueueBrowser是一個專用對象,用來提前瀏覽Queue上的排隊消息,而實際上並沒有真正消費這些消息。
從QueueBrowser獲得的消息是該隊列中消息的副本,而且並未認為會被消費,它們僅僅是用於瀏覽而已。而且,QueueBrowser不能保證提供的是隊列中消息的准確清單,包含的僅僅是創建QueueBrowser時隊列的一個快照,或副本。
五、發布/訂閱消息傳送模型
1、Pub/Sub模型概覽
Pub/Sub模型的特性:
① 信息通過一個稱為主題的虛擬通道進行交換
② 每條信息都會傳送給訂閱者的多個消息消費者
③ 發布者通常不知道哪個訂閱者正在接收主題消息
④ 消息被推送給消費者,消息會傳送給消費者,而無須請求
⑤ 生產者和消費者沒有耦合
⑥ 訂閱一個主題的每個客戶端都會接收到發布該主題的消息副本
發布者不會關心,或者無須擔心信息將被如何使用,它只需將該信息發布給一個主題即可。
2、TBorrower和TLender應用程序
一個抵押信貸提供方發布抵押利率,而一個對最新利率感興趣的借方則訂閱了這個主題。
3、持久訂閱者和非持久訂閱者
只有非持久訂閱者在主動偵聽一個主題時(即活動的,程序處於運行狀態),才會接收到消息。否則,它們就會錯過這些消息。當JMS提供者接收一條消息時,提供者將為每個訂閱者制作該消息的一個副本。如果訂閱者不是活動的,它就不會接收該消息的副本。
持久訂閱者會接收發送到該主題的所有消息,無論該訂閱者活動與否。這稱為“保存並轉發”消息傳送,類似於電子郵件系統。
持久訂閱者是通過在JMS提供者中指定訂閱者名稱(通過配置)並使用createDurableSubscriber方法來創建的,它接受訂閱名稱作為參數之一:TopicSubscriber subscriber=tSession.createDurableSubscriber(topic,“Borrower1”);
六、消息過濾
1、消息選擇器
①使用消息選擇器,可以從一個隊列或主題中過濾出特定的消息。
②消息選擇器是基於SQL-92條件表達式語法的一個子集。
③它使用消息屬性和消息頭作為條件表達式的准則。消息選擇器無法參考消息體內的數據,它只能使用消息頭和消息屬性。
④消息選擇器由三個元素組成:標識符、常量和比較運算符。
2、消息選擇器示例
在創建QueueReceiver、QueueBrowser或TopicSubscriber時,可以將消息選擇器應用於消息消費者。
String selector=”CustomerType=’GOLD’OR JMSPriority BETWEEN 5 AND 9”;
QueueReceiver receiver = session.createReceiver(queue,selector);
3、兩種消息過濾方式
原文地址:http://blog.163.com/nonoliuhao@126/blog/static/1716520942010112871551159/