Rabbitmq mandatory参数和备用交换机

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

    /**
     * Publish a message.
     *
     * Invocations of <code>Channel#basicPublish</code> will eventually block if a
     * <a href="http://www.rabbitmq.com/alarms.html">resource-driven alarm</a> is in effect.
     *
     * @see com.rabbitmq.client.AMQP.Basic.Publish
     * @see <a href="http://www.rabbitmq.com/alarms.html">Resource-driven alarms</a>
     * @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的告知“这条消息无法路由”。

60b0094a777edeb1700265944de7f3d7955.jpg

 

 

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

  /**
     * 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

ac1d5a0af9bb29290d9823be30caac831ff.jpg

 

发送消息

    /**
     * 生产者发送消息
     * @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返回消息给客户端

540823af1d6f7a08aa52d86fc203d6e1e9d.jpg

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

548098d4e4c295cf05998620e9cf2e3689f.jpg

 

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

6978c1a0b006b2ba86188d4de54e1c78f3f.jpg

 

备用交换器

生产者在发送消息的时候如果不设置 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<String, Object> argsMap = new HashMap<String, Object>();
        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 中多了一个参数

9d7044b7ca91c7c45b163c8d59a6b8e73da.jpg

 

声明队列并绑定到交换机

    /**
     * 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

 

9b9c2725eff129b4fa912ebf0e9989be948.jpg

1ddb5a1b3cc5c84a9d371b9635515f04099.jpg

详细源码地址

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

8f3e5648f70ba8e565bc8713542881278fa.jpg

 

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值