Rabbitmq mandatory参数和备用交换机

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

rabbitmq客户端发送消息的方法为basicPublish 这个方法有很多重载的方法。其中有一个方法,里面有一个参数mandatory。当mandatory 参数设为 true 时,交换器无法根据自身的类型和路由键找到一个符合条件的队列,那么 RabbitMq会调用 Basic.Return命令将消息返回给生产者。当mandatory
数设置为 false 时,出现上述情形,则消息直接被丢弃。

    /**
     * Publish a message.
     *
     * Invocations of Channel#basicPublish will eventually block if a
     * resource-driven alarm is in effect.
     *
     * @see com.rabbitmq.client.AMQP.Basic.Publish
     * @see Resource-driven alarms
     * @param exchange the exchange to publish the message to
     * @param routingKey the routing key
     * @param mandatory true if the 'mandatory' flag is to be set
     * @param props other properties for the message - routing headers etc
     * @param body the message body
     * @throws java.io.IOException if an error is encountered
     */
    void basicPublish(String exchange, String routingKey, boolean mandatory, BasicProperties props, byte[] body)
            throws IOException;

简单来说,mandatory 为true时,发送消息到交换机,交换机无法路由该消息,那么发送端可以可以监听到rabbitmq的告知“这条消息无法路由”。

Rabbitmq mandatory参数和备用交换机_第1张图片

 

 

声明交换机、队列 并进行绑定

  /**
     * 1、声明交换机
     */
    @Test
    public void decalreExchange() throws Exception {
        String exchange = "hello_mandatory";
        // 获取到连接
        Connection connection = ConnectionUtil.getConnection();
        // 获取通道
        Channel channel = connection.createChannel();
        // 声明exchange,指定类型为direct
        channel.exchangeDeclare(exchange, BuiltinExchangeType.DIRECT,true,false,false,new HashMap<>());
    }


    /**
     * 2、声明队列并绑定到交换机
     */
    @Test
    public void decalreQueueAndBind() throws Exception {

        String exchange = "hello_mandatory";
        // 获取到连接
        Connection connection = ConnectionUtil.getConnection();
        // 获取通道
        Channel channel = connection.createChannel();
        
        String queueName = "hello_mandatory_c";
        // 声明队列
        channel.queueDeclare(queueName, false, false, false, null);
        // 绑定队列到交换机
        channel.queueBind(queueName, exchange, "aaa");

    }

可以看到队列hello_mandatory_c 绑定到了交换机,routing key 为 aaa

Rabbitmq mandatory参数和备用交换机_第2张图片

 

发送消息

    /**
     * 生产者发送消息
     * @throws Exception
     */
    @Test
    public void sendMessage() throws Exception {
        String exchange = "hello_mandatory";
        // 获取到连接
        Connection connection = ConnectionUtil.getConnection();
        // 获取通道
        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 {
                String message = new String(body);
                log.info("replyText:{}",replyText);
                log.info("exchange:{}",exchange);
                log.info("routingKey:{}",routingKey);
                log.info("message:{}",message);
            }
        });

        String message = "less is more";
        // 发布消息到Exchange 设置mandatory为true
        channel.basicPublish(exchange, "bbb", true, null, message.getBytes());

        // 发布消息到Exchange 设置mandatory为true
        channel.basicPublish(exchange, "aaa", true, null, message.getBytes());
        log.debug("Producer send message:{}", message);
        TimeUnit.SECONDS.sleep(10);
        channel.close();
        connection.close();
    }


可以看到bbb 无法路由 ,rabbitmq返回消息给客户端

Rabbitmq mandatory参数和备用交换机_第3张图片

路由键为aaa的消息成功的发送到了队列hello_mandatory_c

Rabbitmq mandatory参数和备用交换机_第4张图片

 

获取消息,可以看到“less is more”

Rabbitmq mandatory参数和备用交换机_第5张图片

 

备用交换器

生产者在发送消息的时候如果不设置 mandatory 参数那么消息在未被路由的情况下将会丢失,如果设置了 mandatory 参数,那么需要添加 ReturnListener 的编程逻辑,生产者的代码将变得复杂。如果既不想复杂化生产者的编程逻辑,又不想消息丢失,那么可以使用备用交换器,这样可以将未被路由的消息存储在RabbitMQ 中,在需要的时候去处理这些消息。

 

声明交换机

    /**
     * 1、声明交换机
     */
    @Test
    public void decalreExchange() throws Exception {
        String mainExchange = "hello_back_me";
        String backExchange = "hello_back_be";
        // 获取到连接
        Connection connection = ConnectionUtil.getConnection();
        // 获取通道
        Channel channel = connection.createChannel();

        //设置备用交换机
        Map argsMap = new HashMap();
        argsMap.put("alternate-exchange", backExchange);
        // 声明exchange,指定类型为direct
        channel.exchangeDeclare(mainExchange, BuiltinExchangeType.DIRECT, true, false, false, argsMap);

        // 声明exchange,指定类型为fanout
        channel.exchangeDeclare(backExchange, BuiltinExchangeType.FANOUT, true, false, false, new HashMap<>());
    }

可以看到交换机 hello_back_me 中多了一个参数

Rabbitmq mandatory参数和备用交换机_第6张图片

 

声明队列并绑定到交换机

    /**
     * 2、声明队列并绑定到交换机
     */
    @Test
    public void decalreQueueAndBind() throws Exception {

        String mainExchange = "hello_back_me";
        String backExchange = "hello_back_be";
        // 获取到连接
        Connection connection = ConnectionUtil.getConnection();
        // 获取通道
        Channel channel = connection.createChannel();
        String queueName = "hello_back_me_c";
        // 声明队列
        channel.queueDeclare(queueName, false, false, false, null);
        // 绑定队列到交换机
        channel.queueBind(queueName, mainExchange, "aaa");

        // 声明一个队列
        String queueNameBack = "hello_back_be_c";
        // 声明队列
        channel.queueDeclare(queueNameBack, false, false, false, null);
        // 绑定队列到交换机
        channel.queueBind(queueNameBack, backExchange, "");

    }

 

发送消息

    /**
     * 生产者发送消息
     *
     * @throws Exception
     */
    @Test
    public void sendMessage() throws Exception {
        String exchange = "hello_back_me";
        // 获取到连接
        Connection connection = ConnectionUtil.getConnection();
        // 获取通道
        Channel channel = connection.createChannel();

        // 发布消息到Exchange 设置mandatory为false
        channel.basicPublish(exchange, "bbb", false, null, "less is more bbb".getBytes());

        // 发布消息到Exchange 设置mandatory为false
        channel.basicPublish(exchange, "aaa", false, null, "less is more aaa".getBytes());
        log.debug("Producer send success");
        TimeUnit.SECONDS.sleep(10);
        channel.close();
        connection.close();
    }

 

运行后可以看到,bbb无法路由的消息进入了hello_back_be_c

 

Rabbitmq mandatory参数和备用交换机_第7张图片

Rabbitmq mandatory参数和备用交换机_第8张图片

详细源码地址

https://github.com/suzhe2018/rabbitmq-item

Rabbitmq mandatory参数和备用交换机_第9张图片

 

转载于:https://my.oschina.net/suzheworld/blog/3002881

你可能感兴趣的:(Rabbitmq mandatory参数和备用交换机)