【RabbitMQ】消息可靠性投递(二)Exchange->Queue

系列文章:

第二个环节就是消息从交换机路由到队列。在什么情况下,消息会无法路由到正确的队列?可能因为路由键错误,或者队列不存在。有两种方式处理无法路由的消息:

  • 一种就是让服务端回发给生产者
  • 一种是让交换机路由到另一个备份的交换机

1.消息回发

消息回发的方式:使用 mandatory 参数和 ReturnListener

public class ReturnListenerProducer {
    
    
    public static void main(String[] args) throws Exception{
    
    
    
        ConnectionFactory factory = new ConnectionFactory();
        factory.setUri(ResourceUtil.getKey("rabbitmq.uri"));
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
		
		// 添加监听
        channel.addReturnListener(new ReturnListener() {
    
    
            public void handleReturn(int replyCode,
                                     String replyText,
                                     String exchange,
                                     String routingKey,
                                     AMQP.BasicProperties properties,
                                     byte[] body)
                    throws IOException {
    
    
                System.out.println("=========监听器收到了无法路由,被返回的消息============");
                System.out.println("replyText:"+replyText);
                System.out.println("exchange:"+exchange);
                System.out.println("routingKey:"+routingKey);
                System.out.println("message:"+new String(body));
            }
        });

        AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().deliveryMode(2).
                contentEncoding("UTF-8").build();

        // 发送到了默认的交换机上,由于没有任何队列使用这个关键字跟交换机绑定,所以会被退回
        // 第三个参数是设置的mandatory,如果mandatory是false,消息也会被直接丢弃
        channel.basicPublish("","mydirect",true, properties,"只为更好的你".getBytes());

        TimeUnit.SECONDS.sleep(10);

        channel.close();
        connection.close();
    }
}

在SpringAMQP中是ReturnCallback

// 构建RabbitTemplate的Bean时配置
@Bean 
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
    
    
    RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
    
    rabbitTemplate.setMandatory(true);
    // 当消息成功到达exchange,且无法被路由时触发回调,进行消息回发
    rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback(){
    
    
        public void returnedMessage(Message message,
                                    int replyCode,
                                    String replyText,
                                    String exchange,
                                    String routingKey){
    
    
            System.out.println("回发的消息:");
            System.out.println("replyCode: "+replyCode);
            System.out.println("replyText: "+replyText);
            System.out.println("exchange: "+exchange);
            System.out.println("routingKey: "+routingKey);
        }
    });

    return rabbitTemplate;
}

2.进入备份交换机

消息路由到备份交换机的方式:在创建交换机的时候,从属性中指定备份交换机。

Map<String,Object> arguments = new HashMap<String,Object>(); 
arguments.put("alternate-exchange","ALTERNATE_EXCHANGE");// 指定交换机的备份交换机
channel.exchangeDeclare("TEST_EXCHANGE","topic",false,false,false,arguments); // 声明交换机

注:备份交换机是对于在消息路由处失败,还没有进入消息队列的消息,而死信是已经入队,但过期或投递失败的

猜你喜欢

转载自blog.csdn.net/weixin_43935927/article/details/114199350