使用IDEA开发RabbitMQ教程系列(六)RabbitMQ的Return消息机制

版权声明:本文为博主原创文章,如需转载请注明出处,未注明出处的转载都将追究版权责任 https://blog.csdn.net/lhmyy521125/article/details/88080974

1、前言

因网友提到参考源码的需求,已经更新至github 教程测试源码:https://github.com/lhmyy521125/rabbitmq-test

上一篇我们介绍了RabbitMQ生产者确认机制,如果大家对消费者确认机制还不是很清楚可以翻看一下博主使用IDEA开发RabbitMQ教程系列的上一篇文章,在RabbitMQ生产者确认机制,今天我们再针对RabbitMQ的Return机制来详细聊一聊;

在RabbitMQ生产者确认机制一文中,我们提出了一个疑问:
Exchange通过RoutingKey将消息路由至Queue ,这个环节中如果无法路由至Queue队列,如何处理该消息?消息已经路由至Queue队列,却发现没有消费者,又如何处理?,是否也有一样的通知机制告诉我们?

答案是肯定的,那就是Return消息

2、Return消息机制

在谈Return消息机制前,我们回顾一下之前写的 [RabbitMQ的Queue队列和Message详细使用] (https://blog.csdn.net/lhmyy521125/article/details/87875696) 还记得Message发送的方法,basicPublish 方法么?其中介绍了该方法的各项参数,其中 mandatoryimmediate 这两个参数不知道大家还没有没印象?我们来回顾一下:

  • mandatory :当mandatory 参数设为true 时,交换器无法根据自身的类型和路由键找到一个符合条件的队列,那么RabbitMQ 会调用Basic.Return 命令将消息返回给生产者。当mandatory参数设置为false 时,出现上述情形,则消息直接被丢弃;
  • immediate :当imrnediate参数设为true时,如果交换器在将消息路由到队列时发现队列上并不存在任何消费者,那么这条消息将不会存入队列中。当与路由键匹配的所有队列都没有消费者时,该消息会通过Basic.Return返回至生产者

以上两个参数中有调用Basic.Return命令,我们需要channel.addReturnListener来添加ReturnListener 监昕器实现;看以下代码:

   	channel.addReturnListener(new ReturnListener() {
   		@Override
   		public void handleReturn(int replyCode, String replyText, String exchange,
   				String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
   					System.err.println("---------handle  return----------");
   		}
   	});

简单的说区分两个参数: 一个是消息通过交换机无法路由到队列, 一个是消息已经到达队列确没有消费者;

注意: RabbitMQ3.0版本开始去掉了对imrnediate参数的支持,对此RabbitMQ官方解释是:imrnediate参数会影响镜像队列的性能,增加了代码复杂性,建议采用TTL 和DLX 的方法替代(什么是TTL 和DLX 我们将在后面章节再介绍)

下面我们用完整的样例来测试 Return消息机制
生产者:String routingKey = “test.send”; 故意用一个错误的routingKey 以便测试交换机路由不到队列

public class ReturnMsgProducer {

    public static void main(String[] args) throws Exception {
        //1 创建ConnectionFactory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.1.28");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setUsername("toher");
        connectionFactory.setPassword("toher888");
        //2 创建Connection
        Connection connection = connectionFactory.newConnection();
        //3 创建Channel
        Channel channel = connection.createChannel();
        //4 指定我们的消息投递模式: 消息的确认模式
        channel.confirmSelect();
        //5 声明交换机 以及 路由KEY
        String exchangeName = "test_return_exchange";
        //这里故意用一个错误的routingKey 以便测试交换机路由不到队列
        String routingKey = "test.send";
        //6 发送一条消息
        String msg = "Test Return Message";
        //设置mandatory true
        channel.basicPublish(exchangeName, routingKey, true, null, msg.getBytes());
        //7 添加确认监听 我们将返回的参数都打印出来
        channel.addReturnListener(new ReturnListener() {
            @Override
            public void handleReturn(int replyCode, String replyText, String exchange,
                                     String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.err.println("replyCode: " + replyCode);
                System.err.println("replyText: " + replyText);
                System.err.println("exchange: " + exchange);
                System.err.println("routingKey: " + routingKey);
                System.err.println("properties: " + properties);
                System.err.println("body: " + new String(body));
            }
        });
    }

}

消费者:

public class ReturnMsgConsumer {

	public static void main(String[] args) throws Exception {
        //1 创建ConnectionFactory
        ConnectionFactory connectionFactory = new ConnectionFactory() ;
        connectionFactory.setHost("192.168.1.28");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setUsername("toher");
        connectionFactory.setPassword("toher888");
        //2 创建Connection
        Connection connection = connectionFactory.newConnection();
        //3 创建Channel
        Channel channel = connection.createChannel();
		//4 声明
		String exchangeName = "test_return_exchange";
		//指定类型为topic
		String exchangeType = "topic";
        String queueName = "test_return_queue";
		//因为*号代表匹配一个单词
		String routingKey = "return.*";
        //表示声明了一个交换机
		channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);
        //表示声明了一个队列
		channel.queueDeclare(queueName, true, false, false, null);
        //建立一个绑定关系:
		channel.queueBind(queueName, exchangeName, routingKey);
        //5 创建消费者
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                String msg = new String(body, "UTF-8");
                System.out.println("消费端:" + msg);
            }
        };
        //参数:队列名称、是否自动ACK、Consumer
        channel.basicConsume(queueName, true, consumer);
	}

}

最终的运行效果:
在这里插入图片描述

3、结语

本章节主要介绍了RabbitMQ的Return消息机制,大家可以按照上述的样例代码进行测试,即可了解Return消息机制的原理,谢谢大家!

4、导航

上一篇:RabbitMQ可靠性投递生产者确认机制
下一篇:消费端ACK和消费端拒绝

展开阅读全文

没有更多推荐了,返回首页