什么是死信?
死信就是一些在消息队列中由于种种原因未能被及时处理的信息,如消费者返回reject或nack表示消费失败,或者存储于消息队列中时间过长导致信息过期,也或者是消息队列满了,位于消息队列中最开始的信息便类似于溢出一样,也变成了死信,如果不对这些死信处理,那么最后会导致消息的消失。
于是我们可以为队列配置一个交换机,当队列产生死信时,将死信发送给这个交换机,由于交换机仅仅只是用于路由消息到队列,所以再给该交换机指定一个队列,那么这个交换机就被称为死信交换机,队列叫做死信队列,使用死信队列存储死信并统一处理来避免消息的丢失。
基于死信交换机的特点,我们可以给消息加一个存活时间,这个存活时间可以在队列中或者发送时间时指定,当消息过期时,被转到死信交换机,再交给死信队列进行处理,通过添加消息存活时间,我们就可以实现消息的延迟发送
下面就让我们用代码来实现
首先确定用于发送到的普通交换机和队列
//目标交换机
@Bean
public DirectExchange ttlExchange()
{
return new DirectExchange("ttl.direct");
}
//目标队列
@Bean
public Queue ttlQueue()
{
return QueueBuilder.durable("ttl.queue")
.ttl(10000) //在队列指定消息存活时间
.deadLetterExchange("dl.direct") //指定死信交换机
.deadLetterRoutingKey("dl") //指定routintkey用于路由到死信队列
.build();
}
//绑定
@Bean
public Binding dlBind()
{
return BindingBuilder.bind(ttlQueue()).to(ttlExchange()).with("ttl");
}
再设定死信交换机和队列的监听者
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "dl.queue",durable ="true" ),
exchange = @Exchange(name = "dl.direct"),
key = "dl"
))
public void dlListener(String msg)
{
System.out.println("死信队列接收到的消息为: {"+msg+"}");
}
最后就是发送消息了
@Test
public void dlTest()
{
Message build = MessageBuilder.withBody("hello dl".getBytes(StandardCharsets.UTF_8))
.setDeliveryMode(MessageDeliveryMode.PERSISTENT)
.setExpiration("5000") //在发送消息时指定存活时间,队列中与这里同时指定时,数值小的生效
.build();
rabbitTemplate.convertAndSend("ttl.direct","ttl",build);
}
这样就能做到延时消息了
当然我们也能使用Rabbitmq提供的插件DelayExchange进行延时消息的操作,这里就不再阐述了