RabbitMQ 消息的 Confirm 机制与 Return 机制

Confirm 消息确认机制

消息的确认,是指生产者投递消息后,如果 Broker 收到消息,则会给生产者一个应答。生产者能接收应答,用来确定这条消息是否正常的发送到 Broker,这种方式是消息可靠性投递的核心保障。
MyProducer.java

public class MyProducer {
    
    
	public static void main(String[] args) throws Exception {
    
    
		// 创建连接工厂,并进行属性设置
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.0.125");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
		// 获取连接
		Connection connection = connectionFactory.newConnection();
		// 创建信道
		Channel channel = connection.createChannel();
		// 指定消息的投递模式  --消息的确认模式
		channel.confirmSelect();
		
		String exchangeName = "exchange_confirm";
		String routingKey = "test.confirm";
		// 通过信道发送信息
		String msg = "hello, rabbitmq, test confirm ";
		channel.basicPublish(exchangeName, routingKey, null, msg.getBytes());
		// 添加确认监听
		channel.addConfirmListener(new ConfirmListener() {
    
    

			@Override
			public void handleAck(long deliveryTag, boolean multiple) throws IOException {
    
    
				System.out.println("======handle  Ack==========");
			}

			@Override
			public void handleNack(long deliveryTag, boolean multiple) throws IOException {
    
    
				System.out.println("======handle  Nack==========");
			}
			
		});
		
		System.out.println("生产端消息已发送==" + msg);
		// 不关闭连接,要不然监听不到确认消息
		
	}

}

MyConsumer.java

public class MyConsumer {
    
    
	public static void main(String[] args) throws Exception {
    
    
		// 创建连接工厂,并进行属性设置
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.0.125");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
		// 获取连接
		Connection connection = connectionFactory.newConnection();
		// 创建信道
		Channel channel = connection.createChannel();
		// 指定消息的投递模式  --消息的确认模式
		channel.confirmSelect();
		
		String exchangeName = "exchange_confirm";
		String routingKey = "*.confirm";
		String queueName = "queue_confirm";
		
		channel.exchangeDeclare(exchangeName, "topic", true);
		channel.queueDeclare(queueName, true, false, false, null);
		
		channel.queueBind(queueName, exchangeName, routingKey);
		
		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");
                //TODO 自己的业务
                //交换机
                String exchange = envelope.getExchange();
                //路由key
                String routingKey = envelope.getRoutingKey();
                //消息id
                long deliveryTag = envelope.getDeliveryTag();
                //消息内容
                System.err.println("消费端收到 message : " + msg);
			}
		};
		
		channel.basicConsume(queueName, true, consumer);
		
	}
}

启动 MQ 服务,确保交换机和队列已经声明后,执行生产端代码,输出如下:
在这里插入图片描述
说明 Broker 端已成功收到我们发送的消息。

什么情况下触发 noack ?
磁盘写满;MQ 出现异常;queue 容量到达上限等

Return 消息机制

Return 消息机制用于处理一个不可路由的消息。在某些情况下,如果我们在发送消息的时候,当前的 exchange 不存在或者指定路由 key 路由不到,这个时候如果我们需要监听这种不可达的消息,就要使用 Return 消息机制了。
以下为生产端和消费端的代码片段
----生产端代码片段

		String exchangeName = "exchange_return";
		String routingKey = "test.return";
		String routingKeyError = "test.error";
		// 通过信道发送信息
		String msg = "hello, rabbitmq, test return ";
		
		// return 监听
		channel.addReturnListener(new ReturnListener() {
    
    

			@Override
			public void handleReturn(int replyCode,
		            String replyText,
		            String exchange,
		            String routingKey,
		            AMQP.BasicProperties properties,
		            byte[] body)
		        throws IOException{
    
    

				System.out.println("====returnListener print=====");
				System.out.println("replyCode===" + replyCode);
				System.out.println("replyText===" + replyText);
				System.out.println("exchange===" + exchange);
				System.out.println("routingKey===" + routingKey);
				System.out.println("properties===" + properties);
				System.out.println("body===" + new String(body));
			}
			
		});
		
		// mandatory 为 true时,如果消息路由不到,不会删除消息,监听器可接受到该消息,可做后续的处理;
		// mandatory 默认为 false ,如果消息路由不到, Broke 端会自动删除该消息。
	//	channel.basicPublish(exchange, routingKey, mandatory, props, body);
	//	channel.basicPublish(exchangeName, routingKey, true, null, msg.getBytes());
		channel.basicPublish(exchangeName, routingKeyError, true, null, msg.getBytes());
		
		System.out.println("生产端消息已发送==" + msg);

消费端代码片段

		String exchangeName = "exchange_return";
		String routingKey = "*.return";
		String queueName = "queue_return";
		
		channel.exchangeDeclare(exchangeName, "topic", true);
		channel.queueDeclare(queueName, true, false, false, null);
		channel.queueBind(queueName, exchangeName, routingKey);
		
		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");
                //TODO 自己的业务
                //交换机
                String exchange = envelope.getExchange();
                //路由key
                String routingKey = envelope.getRoutingKey();
                //消息id
                long deliveryTag = envelope.getDeliveryTag();
                //消息内容
                System.err.println("消费端收到 message : " + msg);
			}
		};
		
		channel.basicConsume(queueName, true, consumer);

mandatory 为 true时,如果消息路由不到,不会删除消息,监听器可接收到该消息,可做后续的处理;
mandatory 默认为 false ,如果消息路由不到, Broke 端会自动删除该消息,监听器将接收不到该消息。

当生产端使用正确的 routingKey 时,生产端发送的消息能路由到指定队列,消息的收发正常;
当生产端使用不正确的 routingKeyError 时,路由 key 路由不到指定的队列,Return 监听器可以监听到该条消息,可以后续处理该消息。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Alias_fa/article/details/97620180