rabbitmq的多交换机(扇出为例)监听实现

  1. 配置文件,微服务或者单体都可以在yml里配置,也可以写死在java文件.
yaml 复制代码
spring:
  rabbitmq:
    addresses: 127.0.0.1:5672
    username: guest
    password: guest
    virtual-host: /
    connection-timeout: 15000
    #配置rabbitMq启用开关
    enable: true
    listener:
      simple:
        acknowledge-mode: manual
        concurrency: 15
        max-concurrency: 20
  1. 监听处理文件
java 复制代码
package jzy.ziyuan.util.rabbitmq;

import cn.hutool.json.JSONObject;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import jnpf.util.JsonUtil;
import jzy.model.mom.EventMessageMom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

@Component
@ConditionalOnProperty(name = "spring.rabbitmq.enable", havingValue = "true", matchIfMissing = true)
public class MultiExchangeMessageListener {
    private static final Logger logger = LoggerFactory.getLogger(MultiExchangeMessageListener.class);

    @Autowired
    private IdempotentMessageProcessor idempotentProcessor;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 监听来自多个交换机的消息
     */

    // 声明 Direct 交换机、队列,并绑定路由键
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "order.queue", durable = "true"),    // 队列
            exchange = @Exchange(name = "20250917test1", type = ExchangeTypes.FANOUT) // 交换机
    ))
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "user.queue", durable = "true"),    
    @RabbitListener(queues = "#{tempQueue.name}") // 引用临时队列
    public void handleMessage(Message message) throws IOException {
        String messageId = message.getMessageProperties().getMessageId();
        String exchange = message.getMessageProperties().getReceivedExchange();
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        try {
            // 1. 幂等性检查
            if (idempotentProcessor.isProcessed(messageId)) {
                logger.info("消息已处理,跳过重复消费: messageId={}, exchange={}", messageId, exchange);
                // 手动确认消息
                rabbitTemplate.getConnectionFactory().createConnection().createChannel(false)
                        .basicAck(deliveryTag, false);
                return;
            }

            // 2. 处理消息内容
            String messageBody = new String(message.getBody(), "UTF-8");
            String processedMessage = replaceNbspWithSpace(messageBody);

            // 3. 解析消息
            JSONObject jsonObject = JsonUtil.getJsonToBean(processedMessage, JSONObject.class);
            EventMessageMom eventMessage = JsonUtil.getJsonToBean(jsonObject, EventMessageMom.class);

            logger.info("接收来自交换机的消息: exchange={}, messageId={}, content={}",
                    exchange, messageId, eventMessage);

            switch (exchange) {
                default:
                    break;
            }

            // 4. 执行业务逻辑


            // 5. 标记为已处理
            idempotentProcessor.markAsProcessed(messageId);

            // 6. 手动确认消息
            rabbitTemplate.getConnectionFactory().createConnection().createChannel(false)
                    .basicAck(deliveryTag, false);
            logger.info("消息处理成功: messageId={}, exchange={}", messageId, exchange);

        } catch (Exception e) {
            logger.error("消息处理失败: messageId={}, exchange={}", messageId, exchange, e);

            // 业务失败,拒绝消息并放入死信队列
            rabbitTemplate.getConnectionFactory().createConnection().createChannel(false)
                    .basicNack(deliveryTag, false, false); // 不重新入队
        }
    }

    /**
     * 过滤特殊符号
     */
    public static String replaceNbspWithSpace(String str) {
        if (str == null) {
            return null;
        }
        return str.replaceAll("\\u00A0", " ");
    }
}
  1. rabbitmq配置文件
java 复制代码
package jzy.ziyuan.util.rabbitmq;

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class MultiExchangeRabbitConfig {

    // 交换机名称列表 - 可根据实际需求扩展
    public static final String[] EXCHANGE_NAMES = {
            "exchange.20250918logs",
            "exchange.20250918events",
            "exchange.20250918notifications"
    };

    // 交换机类型
    public static final String EXCHANGE_TYPE = "fanout";

    // 死信交换机和队列
    public static final String DLX_EXCHANGE = "20250918exchange.dlx";
    public static final String DLX_QUEUE = "20250918queue.dlx";

    /**
     * 创建死信交换机
     */
    @Bean
    public DirectExchange dlxExchange() {
        return ExchangeBuilder.directExchange(DLX_EXCHANGE)
                .durable(true)
                .build();
    }

    /**
     * 创建死信队列
     */
    @Bean
    public Queue dlxQueue() {
        return QueueBuilder.durable(DLX_QUEUE)
                .build();
    }

    /**
     * 绑定死信队列到死信交换机
     */
    @Bean
    public Binding dlxBinding() {
        return BindingBuilder.bind(dlxQueue())
                .to(dlxExchange())
                .with("dlx.routing.key");
    }

    /**
     * 创建临时队列 - 非持久化、排他、自动删除
     */
    @Bean
    public Queue tempQueue() {
        // 配置死信参数
        Map<String, Object> args = new HashMap<>();
        args.put("x-dead-letter-exchange", DLX_EXCHANGE);
        args.put("x-dead-letter-routing-key", "dlx.routing.key");

        return QueueBuilder.nonDurable()    // 非持久化
                .exclusive()                // 排他队列
                .autoDelete()               // 自动删除
                .withArguments(args)
                .build();
    }

    /**
     * 创建多个交换机并绑定到临时队列
     */
    @Bean
    public Declarables exchangeBindings() {
        Declarables declarables = new Declarables();

        // 创建所有交换机并绑定到临时队列
        for (String exchangeName : EXCHANGE_NAMES) {
            // 创建交换机
            FanoutExchange exchange = ExchangeBuilder.fanoutExchange(exchangeName)
                    .durable(true)
                    .build();
            declarables.getDeclarables().add(exchange);

            // 绑定交换机到临时队列
            Binding binding = BindingBuilder.bind(tempQueue())
                    .to(exchange);
            declarables.getDeclarables().add(binding);
        }

        return declarables;
    }

    /**
     * 配置监听容器工厂 - 手动ACK和QoS设置
     */
    @Bean
    public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); // 手动确认
        factory.setPrefetchCount(10); // QoS设置
        factory.setConcurrentConsumers(3); // 并发消费者数量
        factory.setMaxConcurrentConsumers(5); // 最大并发消费者数量

        // 配置自动重连机制
        factory.setRecoveryInterval(5000L); // 重连间隔5秒

        return factory;
    }
}
相关推荐
斯班奇的好朋友阿法法4 小时前
rabbitmq服务端消费端实例(direct和fanout模式)
分布式·rabbitmq·ruby
没有bug.的程序员4 小时前
分布式架构未来趋势:从云原生到智能边缘的演进之路
java·分布式·微服务·云原生·架构·分布式系统
武话不港14 小时前
RabbitMQ异常,handleDelivery方法异常
分布式·消息队列·rabbitmq
^Moon^9 小时前
CycloneDDS:跨主机多进程通信全解析
c++·分布式·dds
长安城没有风13 小时前
从入门到精通【Redis】Redis 典型应⽤ --- 分布式锁
数据库·redis·分布式
爬山算法16 小时前
Redis(69)Redis分布式锁的优点和缺点是什么?
数据库·redis·分布式
virtuousOne1 天前
Kafka基础
分布式·kafka
虫小宝1 天前
Java分布式架构下的电商返利APP技术选型与架构设计实践
java·分布式·架构
007php0071 天前
百度面试题解析:Zookeeper、ArrayList、生产者消费者模型及多线程(二)
java·分布式·zookeeper·云原生·职场和发展·eureka·java-zookeeper