RabbitMQ笔记二十:Dead Letter Exchange

Dead Letter Exchange

在队列上指定一个Exchange,则在该队列上发生如下情况,
1.消息被拒绝(basic.reject or basic.nack),且requeue=false
2.消息过期而被删除(TTL)
3.消息数量超过队列最大限制而被删除
4.消息总大小超过队列最大限制而被删除

就会把该消息转发到指定的这个exchange
同时也可以指定一个可选的x-dead-letter-routing-key,表示默认的routing-key,如果没有指定,则使用消息的routeing-key(也跟指定的exchange有关,
如果是Fanout类型的exchange,则会转发到所有绑定到该exchange的所有队列)。

拒绝消息或者nack

示列

定义一个队列zhihao.miao.order,其有属性x-dead-letter-exchangezhihao.miao.exchange.pay,往Exchange名为zhihao.miao.exchange.order中发送消息。

zhihao.miao.order队列中发送消息,

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import java.util.concurrent.TimeUnit;

@ComponentScan
public class Application {
    public static void main(String[] args) throws Exception{
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);

        byte[] body = "hello,zhihao.miao".getBytes();

        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setContentType("json");

        Message message = new Message(body,messageProperties);

        rabbitTemplate.send("zhihao.miao.exchange.order","zhihao.miao.order",message);

        TimeUnit.SECONDS.sleep(30);

        context.close();
    }
}

配置类:

import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MQConfig {

    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory factory = new CachingConnectionFactory();
        factory.setUri("amqp://zhihao.miao:[email protected]:5672");
        return factory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        return rabbitAdmin;
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }

}

此时消息端拒绝消费这个消息

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import java.util.concurrent.TimeUnit;

@ComponentScan
public class Application {
    public static void main(String[] args) throws Exception{
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);

        System.out.println(rabbitTemplate);

        TimeUnit.SECONDS.sleep(30);

        context.close();
    }
}

配置类

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MQConfig {

    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory factory = new CachingConnectionFactory();
        factory.setUri("amqp://zhihao.miao:[email protected]:5672");
        return factory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        return rabbitAdmin;
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }


    @Bean
    public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory){
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.setQueueNames("zhihao.miao.order");
        container.setDefaultRequeueRejected(false);
        //手动确认
        container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        container.setMessageListener(new ChannelAwareMessageListener(){
            @Override
            public void onMessage(Message message, Channel channel) throws Exception {
                System.out.println("=====rece msg======");
                System.out.println(new String(message.getBody()));
                //执行拒绝消息
                channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
            }
        });
        return container;
    }
}

因为其指定了x-dead-letter-exchangezhihao.miao.exchange.pay,所以会将消息转发到zhihao.miao.exchange.pay,而因为没有指定x-dead-letter-routing-key,所以会使用默认的发送的消息的route key(zhihao.miao.order)进行路由,而我们zhihao.miao.exchange.pay的路由信息如下,所以会将消息转发到zhihao.miao.auto队列中去。

RabbitMQ笔记二十:Dead Letter Exchange_第1张图片
zhihao.miao.exchange.pay的路由信息
RabbitMQ笔记二十:Dead Letter Exchange_第2张图片
发送二条消息,执行了拒绝策略,所以消息转发到了zhihao.miao.auto队列中

示列2

定义了队列zhihao.miao.order,不仅定义了x-dead-letter-exchange属性,也指定了x-dead-letter-routing-key属性

RabbitMQ笔记二十:Dead Letter Exchange_第3张图片
队列zhihao.miao.order定义
RabbitMQ笔记二十:Dead Letter Exchange_第4张图片
zhihao.miao.exchange.pay的路由信息

显而易见当拒绝了该消息的时候就会转发到了zhihao.miao.exchange.pay,而应该该队列指定了route key为zhihao.miao.pay,所以转发到了zhihao.miao.pay队列中去了。

代码很上面的一样。

总结

上面的示列展示了当定义队列时指定了x-dead-letter-exchangex-dead-letter-routing-key视情况而定),并且消费端执行拒绝策略的时候将消息路由到指定的Exchange中去。我们知道还有二种情况会造成消息转发到死信队列。
一种是消息过期而被删除,可以使用这个方式使的rabbitmq实现延迟队列的作用。还有一种就是消息数量超过队列最大限制而被删除或者消息总大小超过队列最大限制而被删除

参考资料

Dead Letter Exchanges
使用TTL(消息过期)来实现消息延迟

你可能感兴趣的:(RabbitMQ笔记二十:Dead Letter Exchange)