ActiveMQ的Request-Response模式

我們前面的學習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註解,就直接指定了回覆的目的地
在這裏插入圖片描述

測試結果如下:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章