SpringBoot2.x系列教程61--SpringBoot整合MQ之ActiveMQ實現消息傳遞

我在上一章節中,給大家介紹了ActiveMQ,本節中我會介紹Spring Boot中如何整合ActiveMQ,實現消息的創建和消費。

一. Spring Boot中整合ActiveMQ

1. 創建web項目

我們按照之前的經驗,創建一個web程序,並將之改造成Spring Boot項目,具體過程略。

2. 添加依賴包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-activemq</artifactId>
</dependency>

3. 創建application.yml配置文件

#配置activemq
spring:
  activemq:
    #activemq的url
    broker-url: tcp://127.0.0.1:61616
    #用戶名
    user: admin
    #密碼
    password: admin
    pool:
      enabled: false #是否使用線程池
      max-connections: 100 #最大連接數
    #是否信任所有包
    packages:
      trust-all: true
  #默認情況下,activemq使用的是queue模式,如果要使用topic模式,必須設置爲true
  jms:
    pub-sub-domain: true

4. 創建ActiveMQ的配置類

在這個類中創建連接工廠,消息隊列等。

package com.yyg.boot.config;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;

import javax.jms.ConnectionFactory;
import javax.jms.Queue;
import javax.jms.Topic;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/4/14
 * @Description Description
 * //@EnableJms啓用jms功能
 */
@Configuration
@EnableJms
public class ActivemqConfig {

    @Autowired
    private Environment env;

    @Bean
    public ConnectionFactory connectionFactory() {
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
        connectionFactory.setBrokerURL(env.getProperty("spring.activemq.broker-url"));
        connectionFactory.setUserName(env.getProperty("spring.activemq.user"));
        connectionFactory.setPassword(env.getProperty("spring.activemq.password"));
        return connectionFactory;
    }

    /**
     * 實現監聽queue
     */
    @Bean("jmsQueueListenerContainerFactory")
    public JmsListenerContainerFactory<?> queueContainerFactory(ConnectionFactory connectionFactory){
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        //開啓接收topic類型的消息
        factory.setPubSubDomain(false);
        return factory;
    }

    /**
     * 實現監聽topic
     */
    @Bean("jmsTopicListenerContainerFactory")
    public JmsListenerContainerFactory<?> topicContainerFactory(ConnectionFactory connectionFactory){
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setPubSubDomain(true);
        return factory;
    }

    /**
     * 隊列名稱
     */
    @Bean("springboot.queue")
    public Queue queue() {
        return new ActiveMQQueue("springboot.queue") ;
    }

    /**
     * Topic名稱
     */
    @Bean("springboot.topic")
    public Topic topic() {
        return new ActiveMQTopic("springboot.topic") ;
    }

}

5. 創建消息生產者的工具類

在這個Producer類中,創建幾個發送消息的的方法。

package com.yyg.boot.jms;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.jms.Destination;
import javax.jms.Queue;
import javax.jms.Topic;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/4/15
 * @Description 消息生產者
 */
@Slf4j
@Component
public class Producer {

    @Resource(name = "springboot.queue")
    private Queue queue;

    @Resource(name = "springboot.topic")
    private Topic topic;

    @Resource(name = "springboot.replyQueue")
    private Queue replyQueue;

    @Autowired
    private JmsMessagingTemplate jmsTemplate;

    /**
     * 發送消息,destination是發送到的目標隊列,message是待發送的消息內容;
     */
    public void sendMessage(Destination destination, final String message) {
        jmsTemplate.convertAndSend(destination, message);
    }

    /**
     * 發送隊列消息
     */
    public void sendQueueMessage(final String message) {
        sendMessage(queue, message);
    }

    /**
     * 發送Topic消息
     */
    public void sendTopicMessage(final String message) {
        sendMessage(topic, message);
    }

}

6. 定義消費消息的Consumer類

package com.yyg.boot.jms;

import lombok.extern.slf4j.Slf4j;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Component;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/4/15
 * @Description 消息的消費者
 */
@Slf4j
@Component
public class Consumer {

    /**
     * 監聽Queue隊列,queue類型
     */
    @JmsListener(destination="springboot.queue",
            containerFactory = "jmsQueueListenerContainerFactory")
    public void receiveQueue(String text){
        log.warn(this.getClass().getName()+ "-->收到的報文爲:"+text);
    }

    /**
     * 監聽Topic隊列,topic類型,這裏containerFactory要配置爲jmsTopicListenerContainerFactory
     */
    @JmsListener(destination = "springboot.topic",
            containerFactory = "jmsTopicListenerContainerFactory")
    public void receiveTopic(String text) {
        log.warn(this.getClass().getName()+"-->收到的報文爲:"+text);
    }
    
}

7. 創建Controller,發佈消息

package com.yyg.boot.web;

import com.yyg.boot.domain.User;
import com.yyg.boot.jms.Consumer;
import com.yyg.boot.jms.Producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/4/15
 * @Description Description
 */
@RestController
public class MsgController {

    @Autowired
    private Producer producer;

    @Autowired
    private Consumer consumer;

    @GetMapping("/sendQueue")
    public String sendQueueMsg() {
        User user = new User();
        user.setId(1L);
        user.setUsername("一一哥Queue");
        user.setPassword("123");
        producer.sendQueueMessage(user.toString());
        return "發送成功!";
    }

    @GetMapping("/sendTopic")
    public String sendTopicMsg() {
        User user = new User();
        user.setId(2L);
        user.setUsername("一一哥Topic");
        user.setPassword("123456");
        producer.sendTopicMessage(user.toString());
        return "發送成功!";
    }

}

8. 創建入口類

package com.yyg.boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ActiveMQApplication {

    public static void main(String[] args) {
        SpringApplication.run(ActiveMQApplication.class, args);
    }

}

9. 完整項目結構

10. 啓動項目進行測試

測試發送點對點類型的消息

隊列中可以看到成功的收到了消息。

在ActiveMQ中也可以看到出現了springboot.queue隊列,並且隊列中的消息已被消費掉。

測試發送發佈者訂閱者類型的消息

Topic中可以看到成功的收到了消息。

在ActiveMQ中也可以看到出現了springboot.topic隊列,並且隊列中的消息已被消費掉。

二. 回覆消息的實現

我們在上面的基礎之上,進一步實現發送消息後,進行消息的回覆。

1. 改造ActiveMQ類

在該類中添加一個用來接收回復消息的隊列。

/**
* 回覆隊列名稱
*/
@Bean("springboot.replyQueue")
public Queue queueReply() {
        return new ActiveMQQueue("springboot.replyQueue") ;
}

完整的ActivemqConfig代碼:

package com.yyg.boot.config;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;

import javax.jms.ConnectionFactory;
import javax.jms.Queue;
import javax.jms.Topic;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/4/14
 * @Description Description
 * //@EnableJms啓用jms功能
 */
@Configuration
@EnableJms
public class ActivemqConfig {

    @Autowired
    private Environment env;

    @Bean
    public ConnectionFactory connectionFactory() {
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
        connectionFactory.setBrokerURL(env.getProperty("spring.activemq.broker-url"));
        connectionFactory.setUserName(env.getProperty("spring.activemq.user"));
        connectionFactory.setPassword(env.getProperty("spring.activemq.password"));
        return connectionFactory;
    }

    /**
     * 實現監聽queue
     */
    @Bean("jmsQueueListenerContainerFactory")
    public JmsListenerContainerFactory<?> queueContainerFactory(ConnectionFactory connectionFactory){
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        //開啓接收topic類型的消息
        factory.setPubSubDomain(false);
        return factory;
    }

    /**
     * 實現監聽topic
     */
    @Bean("jmsTopicListenerContainerFactory")
    public JmsListenerContainerFactory<?> topicContainerFactory(ConnectionFactory connectionFactory){
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setPubSubDomain(true);
        return factory;
    }

    /**
     * 隊列名稱
     */
    @Bean("springboot.queue")
    public Queue queue() {
        return new ActiveMQQueue("springboot.queue") ;
    }

    /**
     * Topic名稱
     */
    @Bean("springboot.topic")
    public Topic topic() {
        return new ActiveMQTopic("springboot.topic") ;
    }

    /**
     * 回覆隊列名稱
     */
    @Bean("springboot.replyQueue")
    public Queue queueReply() {
        return new ActiveMQQueue("springboot.replyQueue") ;
    }

}

2. 改造Producer類

在Producer類中定義一個新的Queue類,並定義發送消息和消費消息的方法。

@Resource(name = "springboot.replyQueue")
private Queue replyQueue;

/**
* 發送隊列的回覆消息
*/
public void sendQueueMessageReply(String message) {
    sendMessage(replyQueue, message);
}

/**
* 生產者監聽消費者的應答信息
*/
@JmsListener(destination = "replyTo.queue",containerFactory = "jmsQueueListenerContainerFactory")
public void consumerMessage(final String text) {
    log.warn("從replyTo.queue隊列中收到的應答報文爲:" + text);
}

完整的Producer類代碼:

package com.yyg.boot.jms;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.jms.Destination;
import javax.jms.Queue;
import javax.jms.Topic;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/4/15
 * @Description 消息生產者
 */
@Slf4j
@Component
public class Producer {

    @Resource(name = "springboot.queue")
    private Queue queue;

    @Resource(name = "springboot.topic")
    private Topic topic;

    @Resource(name = "springboot.replyQueue")
    private Queue replyQueue;

    @Autowired
    private JmsMessagingTemplate jmsTemplate;

    /**
     * 發送消息,destination是發送到的目標隊列,message是待發送的消息內容;
     */
    public void sendMessage(Destination destination, final String message) {
        jmsTemplate.convertAndSend(destination, message);
    }

    /**
     * 發送隊列消息
     */
    public void sendQueueMessage(final String message) {
        sendMessage(queue, message);
    }

    /**
     * 發送Topic消息
     */
    public void sendTopicMessage(final String message) {
        sendMessage(topic, message);
    }

    /**
     * 發送隊列的回覆消息
     */
    public void sendQueueMessageReply(String message) {
        sendMessage(replyQueue, message);
    }

    /**
     * 生產者監聽消費者的應答信息
     */
    @JmsListener(destination = "replyTo.queue",containerFactory = "jmsQueueListenerContainerFactory")
    public void consumerMessage(final String text) {
        log.warn("從replyTo.queue隊列中收到的應答報文爲:" + text);
    }
    
}

3. 改造Consumer類

在該類中添加接收消息,並且設置回覆消息的方法。

/**
* 回覆給生產者的應答信息
*/
@JmsListener(destination="springboot.replyQueue",containerFactory = "jmsQueueListenerContainerFactory")
@SendTo("replyTo.queue") //消費者應答後通知生產者
public String receiveQueueReply(String text){
    log.warn(this.getClass().getName()+ "-->收到的報文爲:"+text);
    return "回覆的信息爲-->"+text;
}

完整的Consumer類代碼:

package com.yyg.boot.jms;

import lombok.extern.slf4j.Slf4j;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Component;

/**
 * @Author 一一哥Sun
 * @Date Created in 2020/4/15
 * @Description 消息的消費者
 */
@Slf4j
@Component
public class Consumer {

    /**
     * 監聽Queue隊列,queue類型
     */
    @JmsListener(destination="springboot.queue",
            containerFactory = "jmsQueueListenerContainerFactory")
    public void receiveQueue(String text){
        log.warn(this.getClass().getName()+ "-->收到的報文爲:"+text);
    }

    /**
     * 監聽Topic隊列,topic類型,這裏containerFactory要配置爲jmsTopicListenerContainerFactory
     */
    @JmsListener(destination = "springboot.topic",
            containerFactory = "jmsTopicListenerContainerFactory")
    public void receiveTopic(String text) {
        log.warn(this.getClass().getName()+"-->收到的報文爲:"+text);
    }

    /**
     * 回覆給生產者的應答信息
     */
    @JmsListener(destination="springboot.replyQueue",containerFactory = "jmsQueueListenerContainerFactory")
    @SendTo("replyTo.queue") //消費者應答後通知生產者
    public String receiveQueueReply(String text){
        log.warn(this.getClass().getName()+ "-->收到的報文爲:"+text);
        return "回覆的信息爲-->"+text;
    }

}

4. 重新運行,測試消息的回覆功能

調用如下接口,測試消息回覆功能。

此時可以看到控制檯輸出如下信息,說明消息回覆成功。

至此,我們實現了Spring boot中如何整合ActiveMQ。

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