论RabbitMq基础应用——队列监听

环境配置

Windows11
rabbitmq版本:3.12.5(重要)
Erlang版本:Erlang/OTP 25(重要)
注意:rabbitmq和Erlang的版本必须匹配,否则会有不必要的麻烦(重要)
JDK版本:11
Maven版本:maven-3.9.4
springboot版本:v2.7.7
数据库MySQL版本:8.0.26

数据库脚本

sys_mq_config:用于交换机、队列相关配置
mq_faild_retry:MQ消息消费失败,用于重试消费

CREATE TABLE `sys_mq_config` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '逻辑ID',
`exchange` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'MQ交换机',
`queue` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '队列名称',
`mq_status` varchar(3) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '状态',
`create_by` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`mq_version` int DEFAULT '1',
`mq_type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'mq类型(direct、topic、fanout、headers)',
`mq_durable` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '持久化',
`mq_auto_delete` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '自动删除',
`route_key` varchar(255) DEFAULT NULL COMMENT '路由键',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='用于配置MQ动态队列';

INSERT INTO `sys_mq_config` (`id`, `exchange`, `queue`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `mq_type`, `mq_durable`, `mq_autoDelete`, `route_key`) VALUES (1, 'next.big.a', 'next.big.a.1', 'A', 'admin', '2022-08-30 16:44:30', 'admin', '2022-08-30 16:44:30', 1, 'direct', 'true', 'false', 'next.big.a.1');
INSERT INTO `sys_mq_config` (`id`, `exchange`, `queue`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `mq_type`, `mq_durable`, `mq_autoDelete`, `route_key`) VALUES (2, 'next.big.a', 'next.big.a.1', 'A', 'admin', '2022-08-30 16:44:30', 'admin', '2022-08-30 16:44:30', 1, 'direct', 'true', 'false', 'next.big.a.1');
INSERT INTO `sys_mq_config` (`id`, `exchange`, `queue`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `mq_type`, `mq_durable`, `mq_autoDelete`, `route_key`) VALUES (3, 'next.big.a', 'next.big.a.2', 'A', 'admin', '2022-08-30 16:44:30', 'admin', '2022-08-30 16:44:30', 1, 'direct', 'true', 'false', 'next.big.a.2');
INSERT INTO `sys_mq_config` (`id`, `exchange`, `queue`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `mq_type`, `mq_durable`, `mq_autoDelete`, `route_key`) VALUES (4, 'next.big.a', 'next.big.a.3', 'A', 'admin', '2022-08-30 16:44:30', 'admin', '2022-08-30 16:44:30', 1, 'direct', 'true', 'false', 'next.big.a.3');
INSERT INTO `sys_mq_config` (`id`, `exchange`, `queue`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `mq_type`, `mq_durable`, `mq_autoDelete`, `route_key`) VALUES (5, 'next.big.a', 'next.big.a.4', 'A', 'admin', '2022-08-30 16:44:30', 'admin', '2022-08-30 16:44:30', 1, 'direct', 'true', 'false', 'next.big.a.4');
INSERT INTO `sys_mq_config` (`id`, `exchange`, `queue`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `mq_type`, `mq_durable`, `mq_autoDelete`, `route_key`) VALUES (6, 'next.big.a', 'next.big.a.5', 'A', 'admin', '2022-08-30 16:44:30', 'admin', '2022-08-30 16:44:30', 1, 'direct', 'true', 'false', 'next.big.a.5');
INSERT INTO `sys_mq_config` (`id`, `exchange`, `queue`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `mq_type`, `mq_durable`, `mq_autoDelete`, `route_key`) VALUES (7, 'next.big.a', 'next.big.a.6', 'A', 'admin', '2022-08-30 16:44:30', 'admin', '2022-08-30 16:44:30', 1, 'direct', 'true', 'false', 'next.big.a.6');
INSERT INTO `sys_mq_config` (`id`, `exchange`, `queue`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `mq_type`, `mq_durable`, `mq_autoDelete`, `route_key`) VALUES (8, 'next.big.a', 'next.big.a.7', 'A', 'admin', '2022-08-30 16:44:30', 'admin', '2022-08-30 16:44:30', 1, 'direct', 'true', 'false', 'next.big.a.7');

CREATE TABLE `mq_faild_retry` (
`id` int NOT NULL AUTO_INCREMENT,
`message` longtext COLLATE utf8_bin COMMENT '消息内容',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin;

INSERT INTO `mq_faild_retry` (`id`, `message`) VALUES (6, '{"msg":"世界上那么多纷纷扰扰,能真正和你产生关系的不多;外面那么冷,你更要记住那个帮你暖被窝的。"}');
INSERT INTO `mq_faild_retry` (`id`, `message`) VALUES (7, '{"msg":"世界上那么多纷纷扰扰,能真正和你产生关系的不多;外面那么冷,你更要记住那个帮你暖被窝的。","qid":"343355c1-ef92-4cbb-9f5c-2ace0a1505eb"}');
INSERT INTO `mq_faild_retry` (`id`, `message`) VALUES (8, '{"msg":"世界上那么多纷纷扰扰,能真正和你产生关系的不多;外面那么冷,你更要记住那个帮你暖被窝的。","qid":"66d2e539-e7c6-4dc8-a16e-bd4393f33c17"}');
INSERT INTO `mq_faild_retry` (`id`, `message`) VALUES (9, '{"msg":"世界上那么多纷纷扰扰,能真正和你产生关系的不多;外面那么冷,你更要记住那个帮你暖被窝的。","qid":"22591adf-734c-4e89-9e68-45db1a79b489"}');
INSERT INTO `mq_faild_retry` (`id`, `message`) VALUES (10, '{"msg":"世界上那么多纷纷扰扰,能真正和你产生关系的不多;外面那么冷,你更要记住那个帮你暖被窝的。","qid":"cd0a2940-e2c5-4d24-b459-93cb5f3bc791"}');
INSERT INTO `mq_faild_retry` (`id`, `message`) VALUES (11, '{"msg":"世界上那么多纷纷扰扰,能真正和你产生关系的不多;外面那么冷,你更要记住那个帮你暖被窝的。","qid":"ab030d27-3134-43f5-ab79-99778ae29ff9"}');
INSERT INTO `mq_faild_retry` (`id`, `message`) VALUES (12, '{"msg":"世界上那么多纷纷扰扰,能真正和你产生关系的不多;外面那么冷,你更要记住那个帮你暖被窝的。","qid":"81458778-6fd4-44ae-9ecf-536868cc8b4b"}');

RabbitUtil工具类

注:此类功能包含,初始化交换机 队列配置、初始化监听列表、获取已创建的队列、判断是否存在队列、将队列添加到监听列表
获取监听列表、判断该队列是否存在监听列表中、创建交换机 创建队列 交换机绑定队列(直连交换机、主题交换机、扇形交换机、头部交换机)


import com.next.common.mq.entity.SysMqConfig;
import com.next.common.mq.mapper.SysMqConfigMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.HashMap;
import java.util.List;

/**
 * 自定义MQ工具类
 * */
@Component
public class RabbitUtil {

    @Autowired
    RabbitAdmin rabbitAdmin;

    /**
     * 消息监听
     * */
    @Autowired
    SimpleMessageListenerContainer listenerContainer;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    SysMqConfigMapper sysMqConfigMapper;


    /**
     * 初始化交换机 队列配置
     * */
    public void initMqConfig(){
        List<SysMqConfig> sysMqConfigs = sysMqConfigMapper.selectList(null);
        if (!CollectionUtils.isEmpty(sysMqConfigs)){
            sysMqConfigs.forEach(item ->{
                if (item.getMqStatus().equals("A")){//启用状态
                    //不存在则创建队列
                    if (!isExistQueue(item.getQueue())){
                        bindQueueAndExchange(
                            item.getExchange(),
                            item.getQueue(),
                            item.getMqType(),
                            item.getRouteKey(),
                            Boolean.valueOf(item.getMqDurable()),
                            Boolean.valueOf(item.getMqAutoDelete()
                            )
                        );
                    }
                }
            });
        }
    }

    /**
     * 初始化监听列表
     * */
    public void initListenerQueue(){
        List<SysMqConfig> sysMqConfigs = sysMqConfigMapper.selectList(null);
        if (!CollectionUtils.isEmpty(sysMqConfigs)){
            sysMqConfigs.forEach(item ->{
                //不存在则添加
                if (!isExistListenerQueue(item.getQueue())){
                    addListenerQueue(item.getQueue());
                }
            });
        }
    }

    /**
     * 获取已创建的队列
     * */
    public QueueInformation getQueueInfo(String queueName){
        return rabbitAdmin.getQueueInfo(queueName);
    }

    /**
     * 判断是否存在队列
     * */
    public boolean isExistQueue(String queueName){
        try{
            if (StringUtils.isEmpty(getQueueInfo(queueName).getName())){
                return false;
            }
        }catch (Exception e){
            return false;
        }
        return true;
    }

    /**
     * 将队列添加到监听列表
     * */
    public void addListenerQueue(String queueName){
        listenerContainer.addQueueNames(queueName);
    }

    /**
     * 获取监听列表
     * */
    public String[] getListenerQueue(){
        return listenerContainer.getQueueNames();
    }

    /**
     * 队列是否存在监听列表中
     * */
    public boolean isExistListenerQueue(String queueName){
        return CollectionUtils.arrayToList(listenerContainer.getQueueNames()).contains(queueName);
    }


    /**
     * 创建交换机 创建队列 交换机绑定队列
     * */
    public void bindQueueAndExchange(String exchangeName,String queueName,String exchangeType,String routeKey,Boolean durable,boolean autoDelete){
        //声明交换机
        switch (exchangeType){
            //直连交换机
            case "direct":
                createDirect(exchangeName,queueName,routeKey,durable,autoDelete);
                break;
            //主题交换机
            case "topic":
                createTopic(exchangeName,queueName,routeKey,durable,autoDelete);
                break;
            //扇形交换机
            case "fanout":
                createFanout(exchangeName,queueName,durable,autoDelete);
                break;
            //头部交换机
            case "headers":
                createHeaders(exchangeName,queueName,durable,autoDelete);
                break;
            default:
                throw new RuntimeException("交换机类型错误");
        }

    }

    /**
     * 直连交换机
     * */
    public void createDirect(String exchangeName,String queueName,String routeKey,Boolean durable,boolean autoDelete){
        DirectExchange directExchange = new DirectExchange(exchangeName, durable, autoDelete);

        rabbitAdmin.declareExchange(directExchange);
        //声明队列
        Queue queue = new Queue(queueName);
        rabbitAdmin.declareQueue(queue);
        //注册交换机队列
        rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(directExchange).with(routeKey));

    }

    /**
     * 主题交换机
     * */
    public void createTopic(String exchangeName,String queueName,String routeKey,Boolean durable,boolean autoDelete){
        TopicExchange topicExchange = new TopicExchange(exchangeName, durable, autoDelete);

        rabbitAdmin.declareExchange(topicExchange);
        //声明队列
        Queue queue = new Queue(queueName);
        rabbitAdmin.declareQueue(queue);
        //注册交换机队列
        rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(topicExchange).with(routeKey));

    }
    /**
     * 扇形交换机
     * */
    public void createFanout(String exchangeName,String queueName,Boolean durable,boolean autoDelete){
        FanoutExchange fanoutExchange = new FanoutExchange(exchangeName, durable, autoDelete);

        rabbitAdmin.declareExchange(fanoutExchange);
        //声明队列
        Queue queue = new Queue(queueName);
        rabbitAdmin.declareQueue(queue);
        //注册交换机队列
        rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(fanoutExchange));

    }
    /**
     * 头部交换机
     * */
    public void createHeaders(String exchangeName,String queueName,Boolean durable,boolean autoDelete){
        HeadersExchange headersExchange = new HeadersExchange(exchangeName, durable, autoDelete);

        rabbitAdmin.declareExchange(headersExchange);
        //声明队列
        Queue queue = new Queue(queueName);
        rabbitAdmin.declareQueue(queue);
        //注册交换机队列
        HashMap<String, Object> header = new HashMap<>();
        header.put("queue", "*");
        header.put("bindType", "whereAll");
        rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(headersExchange).whereAll(header).match());

    }

}

RabbitMqInit 初始化MQ功能类

注:使用@PostConstruct @Async注解,应用启动过程中初始化MQ配置

import com.next.common.mq.util.RabbitUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Slf4j
@Component
public class RabbitMqInit {

    @Autowired
    RabbitUtil rabbitUtil;

    /**
     * 初始化交换机 队列配置
     * */
    @PostConstruct
    @Async
    public void initMq(){
        log.info("执行初始化MQ队列.....");
        //初始化配置队列
        rabbitUtil.initMqConfig();
        //初始化监听列表
        rabbitUtil.initListenerQueue();
    }

}

RabbitMqConfig配置类

注:设置监听器属性、配置消息确认机制

import com.next.common.mq.listen.RabbitMqListener;
import lombok.SneakyThrows;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMqConfig {

    @Autowired
    private RabbitMqListener messageListener;

    @Autowired
    private CachingConnectionFactory connectionFactory;

    @Bean
    public SimpleMessageListenerContainer listenerContainer(ConnectionFactory connectionFactory) {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
        container.setConcurrentConsumers(1);
        container.setMaxConcurrentConsumers(1);
        container.setAcknowledgeMode(AcknowledgeMode.MANUAL); // RabbitMQ默认是自动确认,这里改为手动确认消息
        //设置监听处理器
        container.setMessageListener(messageListener);
        return container;
    }

    @Bean
    public RabbitAdmin rabbitAdmin() {
        return new RabbitAdmin(connectionFactory);
    }
    @Bean
    public RabbitTemplate rabbitTemplate(){
        RabbitTemplate rabbitTemplate = rabbitAdmin().getRabbitTemplate();
        //开启Mandatory出发回调函数
        rabbitTemplate.setMandatory(true);

        //消息无论是否抵达交换机都执行,ack成功为true,否则为false
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                System.out.println("确认消息送到交换机(Exchange)结果:");
                System.out.println("相关数据:" + correlationData);
                System.out.println("是否成功:" + ack);
                System.out.println("错误原因:" + cause);
            }
        });

        //消息没有抵达队列执行,抵达队列不执行
        rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
            @SneakyThrows
            @Override
            public void returnedMessage(ReturnedMessage returnedMessage) {
                System.out.println("确认消息送到队列(Queue)结果:");
                System.out.println("发生消息:" + new String(returnedMessage.getMessage().getBody(),"utf8"));
                System.out.println("回应码:" + returnedMessage.getReplyCode());
                System.out.println("回应信息:" + returnedMessage.getReplyText());
                System.out.println("交换机:" + returnedMessage.getExchange());
                System.out.println("路由键:" + returnedMessage.getRoutingKey());
            }
        });
        return rabbitTemplate;
    }
}

SysMqService服务类

注:消息发送服务类

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.next.common.mq.mapper.SysMqConfigMapper;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class SysMqService {

    @Autowired
    SysMqConfigMapper sysMqConfigMapper;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    RedisTemplate redisTemplate;

    public String sendMQ(JSONObject param){
        String msg = param.getString("msg");
        String ex = param.getString("ex");
        String queue = param.getString("queue");

        //设置全局唯一消息ID
        String qid = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(qid,"0");
        redisTemplate.expire(qid,10, TimeUnit.MINUTES);
        Map<String, Object> headerValues = new HashMap<>();
        headerValues.put("msg",msg);
        headerValues.put("qid",qid);
        /**
         * 声明消息 (消息体, 消息属性)
         */
        MessageProperties messageProperties = new MessageProperties();
        // 设置消息是否持久化。Persistent表示持久化,Non-persistent表示不持久化
        messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
        messageProperties.setContentType("UTF-8");
        messageProperties.getHeaders().putAll(headerValues);

        Message qMessage = null;
        try {
            qMessage = new Message(JSONUtil.toJsonStr(headerValues).getBytes("UTF-8"), messageProperties);
            rabbitTemplate.convertAndSend(ex,queue,qMessage);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }

        return "success";
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RabbitMQ队列监听器是用于在RabbitMQ监听队列的组件。它可以动态地创建队列,并将队列放入监听器中,以便实时接收并处理队列中的消息。 在Java中,可以使用SimpleMessageListenerContainer类来创建和管理RabbitMQ队列监听器。这个类负责监听队列的添加、移除等操作。它是RabbitMQ中专门用于监听队列的组件。 要使用SimpleMessageListenerContainer类创建队列监听器,首先需要使用@Autowired和@Qualifier注解将RabbitAdmin和SimpleMessageListenerContainer类注入到代码中。然后,可以使用RabbitAdmin的方法来创建队列并将其绑定到交换机上。最后,使用SimpleMessageListenerContainer的方法将队列添加到监听器中并启动监听器。这样,就可以实现对队列中消息的监听和处理了。 另外,在一些配置类中,例如RabbitBootstrapConfiguration类中,可以定义RabbitListenerEndpointRegistry bean来进行监听容器的注册操作。这个bean负责管理和注册RabbitMQ监听器的相关操作。通过定义这个bean,可以更方便地管理和配置RabbitMQ队列监听器。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [springBoot整合rabbitMQ,动态创建队列,动态监听。(三)](https://blog.csdn.net/web15085181368/article/details/124077397)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [springboot-rabbitmq 实现动态配置监听容器](https://blog.csdn.net/m0_46978151/article/details/124875003)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值