一、理解JMS
1、什么是JMS?
JMS即Java消息服務(Java Message Service)應用程序接口,API是一個消息服務的標准或者說是規范,允許應用程序組件基於JavaEE平台創建、發送、接收和讀取消息。它使分布式通信耦合度更低,消息服務更加可靠以及異步性。
我們可以簡單的理解:兩個應用程序之間需要進行通信,我們使用一個JMS服務,進行中間的轉發,通過JMS 的使用,我們可以解除兩個程序之間的耦合。
JMS不是消息隊列,更不是某種消息隊列協議。JMS是Java消息服務接口,是一套規范的JAVA API 接口。
1)這套規范接口由SUN提出,並在2002年發布JMS規范的Version 1.1版本。
2)JMS和消息中間件廠商無關,既然是一套接口規范,就代表這它需要各個廠商進行實現。
3)大部分消息中間件產品都支持JMS 接口規范,eg: 可以使用JMS API來連接Stomp協議的產品(例如ActiveMQ)。
就像您可以使用JDBC API來連接ORACLE或者MYSQL一樣。
2、JMS的消息模型
JMS具有兩種通信模式:(點對點)和(發布/訂閱模式)。
3、JMS中消息的產生和消費
在JMS中,消息的產生和消息是異步的。對於消費來說,JMS的消息者可以通過兩種方式來消費消息。
○ 同步 :訂閱者或接收者調用receive方法來接收消息,receive方法在能夠接收到消息之前(或超時之前)將一直阻塞
○ 異步 :訂閱者或接收者可以注冊為一個消息監聽器。當消息到達之后,系統自動調用監聽器的onMessage方法。
4、對象模型
(1) ConnectionFactory
創建Connection對象的工廠,針對兩種不同的jms消息模型,分別有QueueConnectionFactory和TopicConnectionFactory兩種。可以通過JNDI來查找ConnectionFactory對象。
(2) Destination
Destination,即 消息生產者的 消息發送目標,或者說 消息消費者的 消息來源。
對於消息生產者來說,它的Destination是某個隊列(Queue)或某個主題(Topic);
對於消息消費者來說,它的Destination也是某個隊列或主題(即消息來源)。
所以,Destination實際上就是兩種類型的對象:Queue、Topic。可以通過JNDI來查找Destination。
(3) Connection
Connection表示在客戶端和JMS系統之間建立的鏈接(對TCP/IP socket的包裝)。
Connection可以產生一個或多個Session。
跟ConnectionFactory一樣,Connection也有兩種類型:QueueConnection和TopicConnection。
(4) Session
Session是我們操作消息的接口。可以通過session創建生產者、消費者、消息等。
Session提供了事務的功能。
當我們需要使用session發送/接收多個消息時,可以將這些發送/接收動作放到一個事務中。
同樣,也分QueueSession和TopicSession。
(5) 消息的生產者
消息生產者由Session創建,並用於將消息發送到Destination。
同樣,消息生產者分兩種類型:QueueSender和TopicPublisher。
可以調用消息生產者的方法(send或publish方法)發送消息。
(6) 消息消費者
消息消費者由Session創建,用於接收被發送到Destination的消息。
兩種類型:QueueReceiver和TopicSubscriber。
可分別通過session的createReceiver(Queue)或createSubscriber(Topic)來創建。
當然,也可以session的creatDurableSubscriber方法來創建持久化的訂閱者。
(7) MessageListener
消息監聽器。如果注冊了消息監聽器,一旦消息到達,將自動調用監聽器的onMessage方法。
EJB中的MDB(Message-Driven Bean)就是一種MessageListener。
5、消息的組成
Message主要由三部分組成,分別是Header,Properties和Body, 解釋如下:
- Header: 消息頭,所有類型的這部分格式都是一樣的
- Properties: 屬性,按類型可以分為 應用設置的屬性 , 標准屬性 和 消息中間件定義的屬性
- Body: 消息正文,指我們具體需要消息傳輸的內容。
消息頭
序號 | 屬性名稱 | 說明 | 設置者 |
1 |
JMSDestination |
消息發送的目的地,是一個Topic或Queue | send |
2 |
JMSDeliveryMode |
消息的發送模式,分為NON_PERSISTENT和PERSISTENT,即 持久化的 和 非持久化的 | send |
3 |
JMSMessageID |
消息ID,需要以ID : 開頭 | send |
4 |
JMSTimestamp |
消息發送時的時間,也可以理解為 調用send()方法時的時間,而不是 該消息發送完成的時間 | send |
5 |
JMSCorrelationID |
關聯的消息ID,這個通常用在需要回傳消息的時候 | client |
6 |
JMSReplyTo |
消息回復的目的地,其值為一個Topic或Queue, 這個由發送者設置,但是接收者可以決定是否響應 | client |
7 |
JMSRedelivered |
消息是否重復發送過,如果該消息之前發送過,那么這個屬性的值需要被設置為true, 客戶端可以根據這個屬性的值來 確認這個消息是否重復發送過,以避免重復處理。 |
Provider |
8 |
JMSType |
由消息發送者設置的個消息類型,代表消息的結構,有的消息中間件可能會用到這個,但這個並不是是批消息的種類,比如 TextMessage之類的 |
client |
9 |
JMSExpiration |
消息的過期時間,以毫秒為單位,根據定義,它應該是timeToLive的值再加上發送時的GMT時間,也就是說這個指的是過期 時間,而不是有效期 |
send |
10 |
JMSPriority |
消息的優先級,0-4為普通的優化級,而5-9為高優先級,通常情況下,高優化級的消息需要優先發送 | send |
消息屬性
消息屬性的主要作用是可以對頭信息進行一個額外的補充,畢竟消息頭信息:一是有限,二是很多不能由應用程序設定。
通常,消息屬性可以用在消息選擇器的表達式里,結合起來實現對消息的過濾。
消息屬性的值只能是基本的類型,或者這些基本類型對應的包裝類型。也就是說,不能將一個自定義的對象作為屬性值。
通常情況下,如果能夠放在body里的內容,就不必放在消息屬性里。
消息體
為了適應不同場景下的消息,提高消息存儲的靈活性,JMS定義了幾種具體類型的消息,不同的子類型的消息體也不一樣。
需要注意的是,Message接口並沒有提供一個統一的getBody之類的方法。
消息子接口定義如下:
1)TextMessage: 最簡單的消息接口,用於發送文本類的消息,設置/獲取其body的方法定義如下setText()/getText().
2)StreamMessage: 流式消息接口,里面定義了一系列的對基本類型的set/get方法,
消息發送者可以通過這些方法寫入基本類型的數據,
消息接收者需要按發送者的寫入順序來讀取相應的數據。
3)MapMessage:把消息內容存儲在Map里,本接口定義了一系列對基本類型的的set/get方法,
與StreamMessage不同的是,每個值都對應了一個相應的key,
所以消息接收者不必按順序去讀取數據。
4)ObjectMessage: 將對象作為消息的接口,提供了一個set/get 對象的方法,需要注意的是只能設置一個對象,這個對象可以是一個Collection,但必須是序列化的。
5)BytesMessage: 以字節的形式來傳遞消息的接口,除了提供了對基本類型的set/get,還提供了按字節方式進行set/get。