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", " ");
}
}
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;
}
}