我們前面的學習ActiveMQ模式中都是一方負責發送消息,而另外一方負責處理。而我們實際中的很多應用相當於一種一應一答的過程,需要雙方都能給對方發送消息。於是請求-應答的這種通信方式也很重要,其應用也很普遍。
注意: 請求-應答方式並不是JMS規範系統默認提供的一種通信方式。
這裏我們下來看一看在Spring中是如何實現的,首先我們先來看一看之前ActivaMQ與Spring結合中的消息生產及消費的小例子,其主要如下:
消息生產者配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 查找最新的schemaLocation 訪問 http://www.springframework.org/schema/ -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:amq="http://activemq.apache.org/schema/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.15.7.xsd">
<!-- 配置掃描路徑 -->
<context:component-scan base-package="com.kami"/>
<!-- ActiveMQ連接工廠 -->
<amq:connectionFactory id="amqConnectionFactory" brokerURL="tcp://127.0.0.1:61616" userName="" password=""/>
<!-- Spring Caching連接工廠 -->
<!-- Spring用於管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="amqConnectionFactory"/>
<property name="sessionCacheSize" value="100"/>
</bean>
<!-- Spring JmsTemplate的消息生產者-->
<!-- 定義JmsTemplate的Queue類型 -->
<bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
<constructor-arg ref="connectionFactory"/>
<!-- 點對點Queue模式-->
<property name="pubSubDomain" value="false"/>
</bean>
</beans>
上述是我們之前的例子,這裏在Request-Response模式下,有什麼不同呢?我們發出消息後,希望消息消費者消費了消息後肯定給予消息生產者應答,那麼這裏我們肯定需要添加消息的監聽器,如下:
按照上述消費生產者的配置中,我們添加了監聽消息迴應的監聽器messageResponse
,其實現十分的簡單,就是簡單的將其內容打印出來查看,
@Component
public class MessageResponse implements MessageListener {
@Override
public void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println(textMessage.getJMSCorrelationID());;
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
然後我們在發送消息的時候就需要注意了,之前就是簡單的發送消息就結束了,這裏我們不僅需要發送消息,還要告訴消息的消費者,你消費了消息要給我回應,迴應的地址呢?這裏就要傳遞給消費者,不然消費者無法得知迴應消息的目的地
@Component
public class MessageSender {
@Resource(name = "jmsQueueTemplate")
private JmsTemplate queueTemplate;
@Autowired
private MessageResponse messageResponse;
public void sendQueueMsg(){
queueTemplate.send("test.queue", new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
//TextMessage textMessage = session.createTextMessage("Hello Queue");
//return textMessage;
TextMessage textMessage = session.createTextMessage("Hello Queue");
//創建臨時目的地
Destination destination = session.createTemporaryQueue();
//創建回覆消息的消費者
MessageConsumer messageConsumer = session.createConsumer(destination);
//設置監聽回覆消息的監聽器
messageConsumer.setMessageListener(messageResponse);
//指定消息回覆通道
textMessage.setJMSReplyTo(destination);
//生成相關性ID
textMessage.setJMSCorrelationID(String.valueOf(1));
return textMessage;
}
});
}
}
這裏在消息的發送時,其主要的更改如下紅框處,主要就是給消息添加回應的目的地,其中最下面setJMSCorrelationID()
的作用是什麼呢?主要是爲了辨別我們發出的消息和收到的迴應,使其可以一一對應起來,這樣才能方便我們處理業務邏輯,比如我們在實際使用時,可以傳遞ID等唯一的值,如訂單的ID之類
上述就簡單的完成的消息生產者的改動,接下來看一看消息的消費者,這裏我們還是來先看看消費者原來的xml配置
<?xml version="1.0" encoding="UTF-8"?>
<!-- 查找最新的schemaLocation 訪問 http://www.springframework.org/schema/ -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:amq="http://activemq.apache.org/schema/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.15.7.xsd">
<!-- 配置掃描路徑 -->
<context:component-scan base-package="com.kami"/>
<!-- ActiveMQ連接工廠 -->
<amq:connectionFactory id="amqConnectionFactory" brokerURL="tcp://127.0.0.1:61616" userName="" password=""/>
<!-- Spring Caching連接工廠 -->
<!-- Spring用於管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="amqConnectionFactory"/>
<property name="sessionCacheSize" value="100"/>
</bean>
<!-- 定義Queue監聽器 -->
<jms:listener-container destination-type="queue" container-type="default"
connection-factory="connectionFactory" acknowledge="auto">
<jms:listener destination="test.queue" ref="queueConsumer"/>
</jms:listener-container>
</beans>
原來消息的消費者只需要監聽就可以了,這裏我們就不行了需要添加相關的JmsTemplate,用來發送消息消費後的響應消息,如下:
然後我們在消費消息後,我們就發送響應消息給消息的生產者,如下:
其中ReplyTo
是我們新增的一個類,專門用於消費消息後給生產者發送響應消息,其中send()
方法,需要傳遞的參數,一定需要包括Message,爲什麼呢?因爲Message中包括了生產者傳遞過來的目的地和JMSCorrelationID值
@Component
public class ReplyTo {
@Resource(name = "jmsReplyQueueTemplate")
private JmsTemplate jmsReplyQueueTemplate;
public void send(String replyMsg, Message message) throws JMSException {
jmsReplyQueueTemplate.send(message.getJMSReplyTo(), new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
TextMessage textMessage = session.createTextMessage();
textMessage.setText("已接受到消息,內容爲:" + replyMsg);
textMessage.setJMSCorrelationID(message.getJMSCorrelationID());
return textMessage;
}
});
}
}
這樣就完成了在Spring下ActiveMQ的Request-Response模式,其實簡單點來說,就是讓我們消息的生產者和消費者,既能夠生產消息,又能夠消費消息;在生產者發送消息時,需攜帶接收響應消息的目的地,消費者消費完消息後,就拿到消息中的目的地,進行發送響應消息。
接下來測試結果如下:
接下來我們再來看一看SpringBoot中如何使用Request-Response模式,其實其本質和上述講述也還是一樣的,其實還是使消息的生產者和消費者,既能夠生產消息,又能夠消費消息。
在介紹SpringBoot中的Request-Response模式之前,我們先來回顧上剛剛講述的Spring中的Request-Response模式用法,首先需要消息發送時,創建臨時隊列、消費者、添加監聽器等等,最後調用setJMSReplyTo()
方法指定消息回覆通道,然後消息消費者也是需要通過getJMSReplyTo()
來獲取消息回覆的目的地呀。
這裏是不是發現特別的麻煩,其實我們瞭解其Request-Response模式中,到底想幹什麼,起什麼作用就好了,其實根本無法這麼麻煩,只要定好一個消息隊列,如temp-queue
,然後消費者消費了消息,什麼都不用管,直接向該temp-queue
隊列發送消息就好了,然後消息的生產者在發送消息後,直接就監聽這個temp-queue
隊列等待回覆就好了,這樣我們在發送消息時其實就不用再指定消息回覆通道等等,最多可以給消息添加上相關性IDsetJMSCorrelationID()
即可。
其實在SpringBoot中應用Request-Response模式,就類似我們上述講述的這種方法,這裏詳細代碼參加ActivaMQ與SpringBoot結合,我們直接在其基礎上進行修改
首先我們在消息生成者發送消息時,直接就添加一個監聽器,監聽一個名爲springboot.response
的隊列,如下:
然後我們消息者消費消息時,也是直接向springboot.response
的隊列返回一個消息即可,這裏SpringBoot中爲我們提供了@SendTo
註解,就直接指定了回覆的目的地
測試結果如下: