1、消息变成死信的几种情况
- 消息被拒绝(basic.reject / basic.nack),并且requeue = false
- 消息TTL过期
- 队列达到最大长度
2、核心代码
以下内容基于上一篇springboot整合rabbitmq
2.1 添加死信队列、死信队列与短信队列绑定
RabbitConfig
package com.mine.config;
import java.util.HashMap;
import java.util.Map;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfig {
// 死信队列 交换机标识符
public static final String DEAD_LETTER_EXCHANGE_KEY = "x-dead-letter-exchange";
// 死信队列交换机绑定键标识符
public static final String DEAD_LETTER_ROUTING_KEY = "x-dead-letter-routing-key";
// 短信死信交换机
public static final String EXCHANGE_DEAD_SMS = "dead.sms";
// 死信队列
public static final String QUEUE_DEAD_SMS = "queue_dead_sms";
// 短信死信路由键
public static final String ROUTING_KEY_DEAD_SMS = "dead_sms";
// direct交换机
public static final String EXCHANGE_DIRECT = "mine.direct";
// 队列
public static final String QUEUE_EMAIL = "queue_email";
public static final String QUEUE_SMS = "queue_sms";
// routingKey
public static final String ROUTING_KEY_ALL = "all";
public static final String ROUTING_KEY_EMAIL = "email";
public static final String ROUTING_KEY_SMS = "sms";
// fanout交换机
public static final String EXCHANGE_FANOUT = "mine.fanout";
// 队列
public static final String QUEUE_FANOUT_1 = "queue_fanout_1";
public static final String QUEUE_FANOUT_2 = "queue_fanout_2";
// 新建direct交换机
@Bean
public DirectExchange directExchange() {
return new DirectExchange(EXCHANGE_DIRECT);
}
// 新建邮件队列
@Bean
public Queue queueEmail() {
return new Queue(QUEUE_EMAIL, true);
}
// 新建短信队列
@Bean
public Queue queueSms() {
Map<String, Object> args = new HashMap<String, Object>();
args.put(DEAD_LETTER_EXCHANGE_KEY, EXCHANGE_DEAD_SMS);
args.put(DEAD_LETTER_ROUTING_KEY, ROUTING_KEY_DEAD_SMS);
return new Queue(QUEUE_SMS, true, false, false, args);
}
// 绑定邮件队列
@Bean
public Binding bindingEmail(DirectExchange directExchange, Queue queueEmail) {
return BindingBuilder.bind(queueEmail).to(directExchange).with(ROUTING_KEY_EMAIL);
}
// 绑定短信队列
@Bean
public Binding bindingSms(DirectExchange directExchange, Queue queueSms) {
return BindingBuilder.bind(queueSms).to(directExchange).with(ROUTING_KEY_SMS);
}
// 绑定短信队列ALL
@Bean
public Binding bindingSmsAll(DirectExchange directExchange, Queue queueSms) {
return BindingBuilder.bind(queueSms).to(directExchange).with(ROUTING_KEY_ALL);
}
// 绑定邮件队列ALL
@Bean
public Binding bindingEmailAll(DirectExchange directExchange, Queue queueEmail) {
return BindingBuilder.bind(queueEmail).to(directExchange).with(ROUTING_KEY_ALL);
}
// 新建fanout交换机
@Bean
public FanoutExchange fanoutExchange() {
return new FanoutExchange(EXCHANGE_FANOUT);
}
// 新建fanout队列1
@Bean
public Queue queueFanout1() {
return new Queue(QUEUE_FANOUT_1, true);
}
// 新建fanout队列2
@Bean
public Queue queueFanout2() {
return new Queue(QUEUE_FANOUT_2, true);
}
// 绑定fanout队列1
@Bean
public Binding bindingFanout1(FanoutExchange fanoutExchange, Queue queueFanout1) {
return BindingBuilder.bind(queueFanout1).to(fanoutExchange);
}
// 绑定fanout队列2
@Bean
public Binding bindingFanout2(FanoutExchange fanoutExchange, Queue queueFanout2) {
return BindingBuilder.bind(queueFanout2).to(fanoutExchange);
}
// 新建短信死信交换机
@Bean
public DirectExchange deadSmsExchange() {
return new DirectExchange(EXCHANGE_DEAD_SMS);
}
// 新建短信死信队列
@Bean
public Queue queueDeadSms() {
return new Queue(QUEUE_DEAD_SMS, true);
}
// 绑定短信死信队列
@Bean
public Binding bindingDeadSms(DirectExchange deadSmsExchange, Queue queueDeadSms) {
return BindingBuilder.bind(queueDeadSms).to(deadSmsExchange).with(ROUTING_KEY_DEAD_SMS);
}
}
2.2 修改短信消费者
SmsConsumer
package com.mine.consumer;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class SmsConsumer {
@RabbitListener(queues = "queue_sms")
public void process(Message message, Channel channel) throws Exception {
// 获取消息Id,用消息ID做业务判断
String messageId = message.getMessageProperties().getMessageId();
String content = new String(message.getBody(), "UTF-8");
log.info("接收到短信队列消息:" + content + ",消息ID:" + messageId);
if ("error".equals(content)) {
// 拒绝消息
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
return;
}
// 手动签收
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
2.3 添加死信队列消费者
DeadSmsConsumer
package com.mine.consumer;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class DeadSmsConsumer {
@RabbitListener(queues = "queue_dead_sms")
public void process(Message message, Channel channel) throws Exception {
// 获取消息Id,用消息ID做业务判断
String messageId = message.getMessageProperties().getMessageId();
String content = new String(message.getBody(), "UTF-8");
log.info("接收到短信死信队列消息:" + content + ",消息ID:" + messageId);
// 手动签收
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
3、测试
分别发送【message】和【error】消息,查看rabbitmq控制台和代码日志。