Java初识RabbitMQ一Return消息机制

Java初识RabbitMQ一Return消息机制

什么是Return消息机制

Return消息机制用于处理一些不可路由的消息。正常情况下,消息生产端通过指定一个Exchange和RoutingKey,把消息路由到某一个队列中去,然后消费端监听队列,进行消费。但在某些情况下,如在发送消息的时候,当前的Exchange不存在或者指定的RoutingKey路由不到Queue,这个时候,如果我们需要监听这种不可达的消息, 就要使用Return消息机制(ReturnListener)。
在这里插入图片描述
在基础API中有一个关键的配置项mandatory :

  • 如果为true,则监听器会接收到路由不可达的消息,然后进行后续处理。
  • 如果为false,那么broker会自动删除该消息。
        // mandatory 为 true
        channel.basicPublish(exchange , routingKey , true , null , msg.getBytes());

生产端

我们这里使用的是默认交换机,它的路由规则可以看看下面这篇博客。
Java初识RabbitMQ一交换机(default exchange)

package com.kaven.rabbitmq.api.returnListener;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class Producer {
    // 自己服务器的IP
    private static String ip = "IP";
    // RabbitMQ启动的默认端口,也是应用程序进行连接RabbitMQ的端口
    private static int port = 5672;
    // RabbitMQ有一个 "/" 的虚拟主机
    private static String virtualHost = "/";

    // default exchange
    private static String exchange = "";
    // default exchange 的路由规则: routingKey(test) 将匹配同名的 queue(test)
    private static String routingKey = "test";
    private static String routingKeyError = "test_1";

    public static void main(String[] args) throws IOException, TimeoutException {
        // 1 创建ConnectionFactory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost(ip);
        connectionFactory.setPort(port);
        connectionFactory.setVirtualHost(virtualHost);

        // 2 创建Connection
        Connection connection = connectionFactory.newConnection();

        // 3 创建Channel
        Channel channel = connection.createChannel();

        //4 添加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.out.println("---------- handle return ------------");
                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));
            }
        });

        // 5 发送消息
        String msg = "RabbitMQ: return message";
        String msgError = "RabbitMQ: error return message";
        // mandatory 为 true
        channel.basicPublish(exchange , routingKey , true , null , msg.getBytes());
        channel.basicPublish(exchange , routingKeyError , true,null , msgError.getBytes());
    }
}

消费端

package com.kaven.rabbitmq.api.returnListener;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class Consumer {
    // 自己服务器的IP
    private static String ip = "IP";
    // RabbitMQ启动的默认端口,也是应用程序进行连接RabbitMQ的端口
    private static int port = 5672;
    // RabbitMQ有一个 "/" 的虚拟主机
    private static String virtualHost = "/";

    // default exchange
    private static String exchange = "";
    // 队列名
    private static String queueName = "test";

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        // 1 创建ConnectionFactory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost(ip);
        connectionFactory.setPort(port);
        connectionFactory.setVirtualHost(virtualHost);

        // 2 创建Connection
        Connection connection = connectionFactory.newConnection();

        // 3 创建Channel
        Channel channel = connection.createChannel();

        // 4 创建Queue
        channel.queueDeclare(queueName , true , false , false , null);

        // 5 创建消费者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(queueName , true , consumer);

        // 6 接收消息
        while (true){
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String msg = new String(delivery.getBody());
            System.out.println(msg);
        }
    }
}

测试

根据生产端和消费端的代码可以知道,RoutingKey = "test_1"的消息是路由不到对应的Queue,因为我们这里是没有定义名称为 test_1的队列,从RabbitMQ Management可以看到,目前已经定义的Queue。
启动生产端,从RabbitMQ Management可以看到,名称为test的队列有一条消息已经准备好了。
在这里插入图片描述
生产端输出:

---------- handle return ------------
replyCode:312
replyText:NO_ROUTE
exchange:
routingKey:test_1
properties:#contentHeader<basic>(content-type=null, content-encoding=null, headers=null, delivery-mode=null, priority=null, correlation-id=null, reply-to=null, expiration=null, message-id=null, timestamp=null, type=null, user-id=null, app-id=null, cluster-id=null)
body:RabbitMQ: error return message

显然结果是正确的。

启动消费端,输出如下:

RabbitMQ: return message

显然消费端已经收到消息了。

RabbitMQ Management可以看到,名称为test的队列没有准备好的消息,因为已经被消费端接收了。
在这里插入图片描述

再来试一下mandatoryfalse的情况,生产端需要修改代码,消费端不需要修改代码。

生产端:

package com.kaven.rabbitmq.api.returnListener;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class Producer {
    // 自己服务器的IP
    private static String ip = "IP";
    // RabbitMQ启动的默认端口,也是应用程序进行连接RabbitMQ的端口
    private static int port = 5672;
    // RabbitMQ有一个 "/" 的虚拟主机
    private static String virtualHost = "/";

    // default exchange
    private static String exchange = "";
    // default exchange 的路由规则: routingKey(test) 将匹配同名的 queue(test)
    private static String routingKey = "test";
    private static String routingKeyError = "test_1";

    public static void main(String[] args) throws IOException, TimeoutException {
        // 1 创建ConnectionFactory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost(ip);
        connectionFactory.setPort(port);
        connectionFactory.setVirtualHost(virtualHost);

        // 2 创建Connection
        Connection connection = connectionFactory.newConnection();

        // 3 创建Channel
        Channel channel = connection.createChannel();

        //4 添加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.out.println("---------- handle return ------------");
                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));
            }
        });

        // 5 发送消息
        String msg = "RabbitMQ: return message";
        String msgError = "RabbitMQ: error return message";
        // mandatory 为 false
        channel.basicPublish(exchange , routingKeyError , false,null , msgError.getBytes());
    }
}

启动生产端,生产端的ReturnListener并没有被调用(没有输出),看看RabbitMQ Management,也没有消息准备好,broker会自动删除这条消息。
在这里插入图片描述

在这里插入图片描述

发布了293 篇原创文章 · 获赞 338 · 访问量 71万+

猜你喜欢

转载自blog.csdn.net/qq_37960603/article/details/104277969