AMQ學習筆記 - 08. Spring-JmsTemplate之發送


概述


JmsTemplate提供了3組*3,共計9個發送用的方法。
 
發送的方法有3組:
  1. 基本的發送
  2. 轉換並發送
  3. 轉換、后處理再發送

必需的資源


必需的資源有:
  • javax.jms.ConnectionFactory
    ConnectionFactory是客戶端編程的開始,由它依次獲取Connection、Session、Message、MessageProducer或MessageConsumer,從而做好了發送或接收的准備。
  • javax.jms.Destination
    Destination是發送的目的地,或者接收的源
實際上,我們提供了上述的資源之后,我們就是做了這樣的指令:讓JmsTemplate連接到 Destination,從我們提供的 ConnectionFactory中獲取連接資源。
P.S.如果你不了客戶端編程模型,建議參考 02. JMS客戶端編程模型

1.ConnectionFactory資源

我們如何提供ConnectionFactory給JmsTemplate?憑借 JmsTemplete提供的構造器或setter方法:
  • public JmsTemplate(ConnectionFactory connectionFactory)
  • public void setConnectionFactory(ConnectionFactory connectionFactory)
    # 繼承自org.springframework.jms.support.JmsAccessor

2.Destination資源

我們如何提供 Destination給JmsTemplate?
我們有兩個機會做這件事,第一次是在初始化的時候提供一個默認的Destination,第二次是在發送的時候提供一個明確的Destination。相關的方法:
  • public void setDefaultDestination(Destination destination)
    設置默認的Destination
  • public void send(Destination destination, MessageCreator messageCreator)
    將消息發送到指定的Destination
    MessageCreator接口用來提供創建消息的回調方法,后面再講。
 
JmsTemplate還提供了另一種獲取Destination的方式:基於Destination解析器、Destination類型、Destination名字的獲取。你可以使用下面的代碼來指定解析器、Destination類型:
1 // jt is instance of JmsTemplate
2 jt.setDestinationResolver(new DynamicDestinationResolver()); // set Destination解析器
3 jt.setPubSubDomain(false); // set Destinantion類型
Destination解析器要實現org.springframework.jms.support.destination.DestinationResolver接口。解析器有默認的值,就是DynamicDestinationResolver,除非你要使用其他的解析器,否則不必調用setDestinationResolver。所以,第2行代碼是多余的。
Destination類型有2個:false-Queue類型,true-Topic類型;默認為false。所以,第3行代碼是多余的。
設置了解析器、類型,或者直接使用默認的值,之后,就可以設置destination的name。JmsTemplate提供了兩個方法:
  • public void setDefaultDestinationName(String destinationName)
    設置defaultDestination。這個方法和setDefaultDestination(Destination destination)做同樣的事情,只是這個方法依賴於解析器和類型。
  • public void send(String destinationName, MessageCreator messageCreator)
    將消息發送到指定的Destination。這個方法和send(Destination destination, MessageCreator messageCreator)做同樣的事情,只是這個方法依賴於解析器和類型。
 
P.S.如何根據destinationName創建Destination實例?
javax.jms.Session提供了兩個方法,分別創建兩種類型的Destination:
  • Queue createQueue(java.lang.String queueName)
    根據name創建Queue類型的Destination
  • Topic createTopic(java.lang.String topicName)
    根據name創建Topic類型的Destination
我們看下DynamicDestinationResolver的源碼:
 1 public class DynamicDestinationResolver implements DestinationResolver {
 2     @Override
 3     public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
 4             throws JMSException {
 5         Assert.notNull(session, "Session must not be null");
 6         Assert.notNull(destinationName, "Destination name must not be null");
 7         if (pubSubDomain) {
 8             return resolveTopic(session, destinationName);
 9         }
10         else {
11             return resolveQueue(session, destinationName);
12         }
13     }
14     protected Topic resolveTopic(Session session, String topicName) throws JMSException {
15         return session.createTopic(topicName);
16     }
17     protected Queue resolveQueue(Session session, String queueName) throws JMSException {
18         return session.createQueue(queueName);
19     }
20 }

根據這份源碼,可以幫助理解pubSubDomain的機制,以及將JMS的api和Spring的Destination解析器這兩個知識點連接起來。

1.基本的發送方法


在前文我們已經接觸了兩個,它們都是在發送的同時指定Destination。現把它們和第3種一起介紹:
  • public void send(Destination destination, MessageCreator messageCreator)
    將消息發送到指定的Destination
  • public void send(String destinationName, MessageCreator messageCreator)
    將消息發送到指定的Destination。這個方法和send(Destination destination, MessageCreator messageCreator)做同樣的事情,只是這個方法依賴於解析器和類型。
  • public void send(MessageCreator messageCreator)
    將消息發送到defaultDestination。
    這個方法要求提前設置
    defaultDestination,你可以調用setDefaultDestination(Destination destination)或者setDefaultDestinationName(String destinationName)來滿足這個前提。
在3個基本的發送方法中,都使用MessageCreator來創建消息。

使用MessageCreator創建消息

jms中的Message,是以接口javax.jms.Message為首的接口家族,這個家族的圖譜是這樣的:
javax.jms.Message
    |---- BytesMessage
    |---- MapMessage
    |---- ObjectMessage
    |---- StreamMessage
    |---- TextMessage
JMS將Message細分為5種類型,並在javax.jms.Session接口中分別定義了創建上述Message的多個方法,通常以create*Message為名,返回對應的Message類型。
 
在JMS的api中,只有javax.jms.Session能創建消息。
 
所以在Spring中,如果我們要創建 Message,就要有Session。但是我們只有現成的ConnectionFactory,我們不應該走一遍從ConnectionFactory到Session的路,否則我們也不需要JmsTemplate幫我們發送了,因為剩下的工作也沒多少了——關鍵是我們並沒有從JMS的API中解脫出來。
所以有了 MessageCreator的接口,它定義了一個回調的方法:
  • Message createMessage(Session session)
只要我們把MessageCreator的實例傳給JmsTemplate,它就會在合適的時候調用這個方法,並發送返回的消息。
下面給一個例子:
1 jt.send(DESTINATION_NAME, new MessageCreator() {
2     
3     public Message createMessage(Session session) throws JMSException {
4         String text = "A test for MessageCreator.";
5         Message message = session.createTextMessage(text);
6         return message;
7     }
8 });

2.轉換並發送的方法


我們需要將數據裝進JMS的Message,然后再發送。JMS的Message有5種具體的類型,不同的類型適合裝載不同的數據。如果你不想做這段工作,而是希望能直接把數據丟給誰,然后由它來封裝成Message——你只想准備數據,然后發送。那么接下來要介紹的方法,正適合你。
 
Spring為轉換定義了一個接口:org.springframework.jms.support.converter.MessageConverter,這個接口定義了下面的兩個方法:
  • Message toMessage(Object object, Session session)
    發送時用到
  • Object fromMessage(Message message)
    接收時用到
一般情況下,我們既不需要為 MessageConverter提供實現,也不需要面向 MessageConverter進行編程,所以我們實在沒有必要關注上面的兩個方法,掃一眼,有個大概的印象就夠了。
 
說回JmsTemplate,它定義了下面的方法來設置Converter:
  • public void setMessageConverter(MessageConverter messageConverter)
而且在初始化的時候,會自動賦值一個SimpleMessageConverter類型的實例,所以我們甚至也不需要關心 setMessageConverter方法了。
 
說了這不多,總結一下,如果要用到轉換,我們需要多做什么工作? 答案是不需要!
下面是具有轉換功能的發送的方法,與基本的發送的方法進行對比:
轉換發送 基本發送
  • public void convertAndSend(Destination destination, Object message)
    將message轉換成JMS的Message,並發送到指定的Destination
  • public void convertAndSend(String destinationName, Object message)
    將message轉換成JMS的Message,並發送到指定的Destination。
  • public void convertAndSend(Object message)
    將message轉換成JMS的Message,並發送到defaultDestination。
  • public void send(Destination destination, MessageCreator messageCreator)
    將消息發送到指定的Destination
  • public void send(String destinationName, MessageCreator messageCreator)
    將消息發送到指定的Destination。
  • public void send(MessageCreator messageCreator)
    將消息發送到defaultDestination。
這兩個系列的方法相似度很高,只是在創建消息的問題上有不同的處理:轉換發送隱藏了消息的創建,基本發送需要實現 MessageCreator接口來創建消息。
 
接下來是一個demo,我們將上面的demo也拿下來,做一個對比:
轉換發送
1 String message = "a message for test convertAndSend.";
2 jt.convertAndSend(DESTINATION_NAME, message);
基本發送
1 jt.send(DESTINATION_NAME, new MessageCreator() {
2     
3     public Message createMessage(Session session) throws JMSException {
4         String text = "A test for MessageCreator.";
5         Message message = session.createTextMessage(text);
6         return message;
7     }
8 }); 
2比8,這純粹是數學問題了。

3.轉換、后處理再發送的方法


javax.jms.Message定義了很多的方法用來為消息添加頭部信息或屬性。但是如果我們要用轉換並發送的方法,我們就接觸不到Message類型的消息了,自然也無法為其添加任何信息。JmsTemplate提供了另一套發送的方法,允許我們使用自動轉換,還允許我們能接觸到轉換后的消息,以便我們能做些什么。之后我們會返回處理后的Message,交給JmsTemplate發送。
 
Spring定義了org.springframework.jms.core.MessagePostProcessor接口來做后處理的事,它定義了一個唯一的方法:
  • Message postProcessMessage(Message message)
    對消息進行處理,並返回處理后的消息
 
讓我們來看看這些方法,並與前文介紹的方法對比:
轉換、后處理、發送 轉換、發送
  • public void convertAndSend(Destination destination, Object message, MessagePostProcessor postProcessor)
  • public void convertAndSend(String destinationName, Object message, MessagePostProcessor postProcessor)
  • public void convertAndSend(Object message, MessagePostProcessor postProcessor)
  • public void convertAndSend(Destination destination, Object message)
    將message轉換成JMS的Message,並發送到指定的Destination
  • public void convertAndSend(String destinationName, Object message)
    將message轉換成JMS的Message,並發送到指定的Destination。
  • public void convertAndSend(Object message)
    將message轉換成JMS的Message,並發送到defaultDestination。
再來看看兩個demo的對比:
轉換、后處理、發送
1 String message = "a message for test convertProcessAndSend.";
2 jt.convertAndSend(DESTINATION_NAME, message,
3         new MessagePostProcessor() {
4             public Message postProcessMessage(Message message)
5                     throws JMSException {
6                 message.setIntProperty("order", 1);
7                 return message;
8             }
9         }); 
轉換、發送
1 String message = "a message for test convertAndSend.";
2 jt.convertAndSend(DESTINATION_NAME, message); 
在轉換、后處理、發送中,我們為Message設置了一個屬性:order=1.






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM