RabbitMQ之Confirm确认机制、Return消息机制

文章详细阐述了RabbitMQ中的Confirm消息确认机制,包括开启确认模式、添加确认监听器以确保消息可靠投递。同时,介绍了Return消息机制,用于处理不可路由的消息,通过ReturnListener监听并处理这些情况。文中提供了生产端和消费端的示例代码来说明这两个机制的工作原理。

Confirm确认机制、Return消息机制都是在生产端进行操作。

一、Confirm确认消息

1. 理解Confirm消息确认机制

消息的确认,是指生产者投递消息后,如果Broker(MQ server节点)收到消息,则会给我们生产者一个应答。

生产者对应答进行接收,用来确认这条消息是否正常的发送到Broker,这种方式也是消息的可靠性投递的核心保障。

2. 如何实现Confirm消息确认

第一步:在channel上开启确认模式:channel:confirmSelect()

第二步:在channel上添加监听:addConfirmListener,监听成功和失败的返回结果,根据具体的结果对消息进行重新发送、或记录日志等待后续处理!

示例代码:

    // 生产端:发送消息
    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("121.43.153.00");
        factory.setPort(5672);
        factory.setVirtualHost("/");

        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        String exchangeName = "confirm_exchange";
        String routingKey = "confirm.a";

        AMQP.BasicProperties props = new AMQP.BasicProperties().builder()
                .deliveryMode(2)
                .contentEncoding("UTF-8")
                .headers(new HashMap<>())
                .build();

        String msg = "hello, i am a message for confirm-test";

        // 下面两个操作:confirmSelect()、addConfirmListener()是实现confirm机制的关键代码
        channel.confirmSelect();
        channel.addConfirmListener(new ConfirmListener() {
            @Override
            public void handleAck(long deliveryTag, boolean multiple) throws IOException 
            {
                System.out.println("handleAck OK");
            }

            @Override
            public void handleNack(long deliveryTag, boolean multiple) throws IOException 
            {
                System.err.println("handleNack ERROR");
            }
        });
        channel.basicPublish(exchangeName, routingKey, props, msg.getBytes());
    }

    // 消费端:消费消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("121.43.153.00");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setAutomaticRecoveryEnabled(true);
        factory.setNetworkRecoveryInterval(3000);

        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        String exchangeName = "confirm_exchange";
        String queueName = "confirm_queue";
        String exchangeType = "topic";
        String routingKey = "confirm.*";

        channel.exchangeDeclare(exchangeName, exchangeType, false, false, null);
        channel.queueDeclare(queueName, false, false, false, null);
        channel.queueBind(queueName, exchangeName, routingKey);

        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(queueName, false, consumer);

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            System.out.println("Receive Message:"+ new String(delivery.getBody()));
            // 手动应答
            channel.basicNack(delivery.getEnvelope().getDeliveryTag(), false, false);
        }
    }

二、Return消息机制

Return Listener 用于处理一些不可路由的消息。

我们的消息生产者,通过指定一个Exchange和RoutingKey,把消息送达到某一个队列中去,然后我们的消费监听队列,进行消费处理操作。

但是在某些情况下,如果我们在发送消息的时候,当前的exchange不存在或者指定的路由key路由不到,这个时候如果我们需要监听这种不可达的消息,就是使用Return Listener!

另外在基础API中有一个关键的配置项:Mandatory,如果为true,则 Return Listener 会接收到路由不可达的消息,然后进行后续处理,如果为false,那么Broker端会自动删除该消息,Return Listener不会收到该消息。

示例代码:

    // 生产端:发送消息
    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("121.43.153.00");
        factory.setPort(5672);
        factory.setVirtualHost("/");

        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        String exchangeName = "return_exchange";
        String routingKey = "returnb";
        String msg = "message for return-test";

        AMQP.BasicProperties props = new AMQP.BasicProperties().builder()
                .headers(new HashMap<>())
                .contentEncoding("UTF-8")
                .deliveryMode(2)
                .build();
        // 实现 return listener 监听器
        channel.addReturnListener(new ReturnListener() {
            @Override
            public void handleReturn(int replyCode,
                                     String replyText,
                                     String exchange,
                                     String routingKey,
                                     AMQP.BasicProperties properties,
                                     byte[] body) {
                System.out.println("replyCode:"+replyCode);
                System.out.println("replyText:"+replyText   );
                System.out.println("exchange:"+exchange);
                System.out.println("routingKey:"+routingKey);
                System.out.println("body:"+new String(body));
            }
        });
        channel.basicPublish(exchangeName, routingKey, true, props,  msg.getBytes());
    }

    // 消费端:消费消息
    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("121.43.153.00");
        factory.setPort(5672);
        factory.setVirtualHost("/");

        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        String exchangeName = "return_exchange";
        String routingKey = "returnb";
        String msg = "message for return-test";

        AMQP.BasicProperties props = new AMQP.BasicProperties().builder()
                .headers(new HashMap<>())
                .contentEncoding("UTF-8")
                .deliveryMode(2)
                .build();
        channel.addReturnListener(new ReturnListener() {
            @Override
            public void handleReturn(int replyCode,
                                     String replyText,
                                     String exchange,
                                     String routingKey,
                                     AMQP.BasicProperties properties,
                                     byte[] body) {
                System.out.println("replyCode:"+replyCode);
                System.out.println("replyText:"+replyText   );
                System.out.println("exchange:"+exchange);
                System.out.println("routingKey:"+routingKey);
                System.out.println("body:"+new String(body));
            }
        });
        // 如果想让 return listener 监听到,这里要设置为 true
        boolean mandatory = true;
        channel.basicPublish(exchangeName, routingKey, mandatory, props,  msg.getBytes());
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值