channel error; protocol method: #method<channel.close>(reply-code=406...

2,615 阅读2分钟

在使用 rabbitMq 中间件对数据进行存读的时候,使用 fanout 交换机出现了问题,报了以下错误。

一、原报错信息:

java.io.IOException
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:129)
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:125)
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:147)
at com.rabbitmq.client.impl.ChannelN.exchangeDeclare(ChannelN.java:783)
at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.exchangeDeclare(AutorecoveringChannel.java:252)
at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.exchangeDeclare(AutorecoveringChannel.java:242)
at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.exchangeDeclare(AutorecoveringChannel.java:232)
at com.yuqn.ServerTwoController.main(ServerTwoController.java:42)

Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method\<channel.close>(reply-code=406, reply-text=PRECONDITION\_FAILED - inequivalent arg 'type' for exchange 'fanoutExchange' in vhost '/': received 'fanout' but current is 'direct', class-id=40, method-id=10)
at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66)
at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:36)
at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:502)
at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:293)
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:141)
... 5 more
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - inequivalent arg 'type' for exchange 'fanoutExchange' in vhost '/': received 'fanout' but current is 'direct', class-id=40, method-id=10)
at com.rabbitmq.client.impl.ChannelN.asyncShutdown(ChannelN.java:517)
at com.rabbitmq.client.impl.ChannelN.processAsync(ChannelN.java:341)
at com.rabbitmq.client.impl.AMQChannel.handleCompleteInboundCommand(AMQChannel.java:182)
at com.rabbitmq.client.impl.AMQChannel.handleFrame(AMQChannel.java:114)
at com.rabbitmq.client.impl.AMQConnection.readFrame(AMQConnection.java:739)
at com.rabbitmq.client.impl.AMQConnection.access$300(AMQConnection.java:47)
at com.rabbitmq.client.impl.AMQConnection\$MainLoop.run(AMQConnection.java:666)
at java.lang.Thread.run(Thread.java:748)
Disconnected from the target VM, address: '127.0.0.1:61201', transport: 'socket'

二、源代码:

public static void main(String[] args) {
    // 创建连接工厂
    ConnectionFactory factory = new ConnectionFactory();
    // rabbitmq配置
    factory.setHost("localhost");
    factory.setPort(5672);
    factory.setUsername("guest");
    factory.setPassword("guest");
    //定义连接
    Connection connection = null;
    //定义通道
    Channel channel = null;
    // 获取消息
    try {
        // 获取连接
        connection = factory.newConnection();
        // 获取通道
        channel = connection.createChannel();
        /*
        * 由于fanout类型的交换机的消息队列类似于广播的模式,不需要绑定RoutingKey
        * 而且又可能存在多个消费者来接收这个交换机的数据,所以我们创建队列是要创建
        * 一个随机的队列名称
        *
        * 没有参数的queueDeclare方法会创建一个名字为随机的一个队列
        * 这个队列的数据是非持久化的
        * 是排外的(同时最多值允许一个消费者监听到当前队列)
        * 是自动删除的,当没有任何消费者监听队列使这个队列会自动删除
        *
        * getQueue() 方法用于获取这个随机的队列名
        * */
        String queueName = channel.queueDeclare().getQueue();

        // 声明交换机
        channel.exchangeDeclare("fanoutExchange","fanout",true);
        /*
         * 绑定交换机
         * 参数一:队列名称
         * 参数二:交换机名称
         * 参数三:消息的RoutingKey(就是BindingKey)
         * 注:
         * 1、在进行队列队列和交换机绑定时必须要确保交换机和队列已经成功声明
         * */
        channel.queueBind(queueName,"fanoutExchange","");
        /*
         * 接收消息
         * 参数一:消费者需要监听的队列名
         * 参数二:拿到消息后是否自动移除消息
         * 参数三:消息接受者的标签,用于多个消费者同时监听同一个队列时,通常用于标记不同的消费者,通常为空字符串
         * 参数四:消息接收的回调方法,表示对拿到的消息进行处理
         * 注意:使用basicConsume后会自动开启一个线程,如果有数据进入,会自动接收,所以连接通道不能关闭
         * */
        channel.basicConsume(queueName,true,"",new DefaultConsumer(channel){
            // 消息的具体接收和处理
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body,"utf-8");
                System.out.println("接收信息"+message);
            }
        });

    } catch (IOException e) {
        e.printStackTrace();
    } catch (TimeoutException e) {
        e.printStackTrace();
    }
}

三、问题分析:

因为一开始在使用 channel.exchangeDeclare("fanoutExchange","fanout",true) 声明交换机的时候,参数类型写成direct,并且启动,导致在RabbitMq中已经存在一个direct类型的交换机。

image.png

四、解决方法:

将交换机移除掉,重新启动项目即可。

image.png

移除交换机后,重新启动项目,已经能够正常启动了。

image.png

五、参考代码:

github:https://github.com/Yuqn/rabbitMqProject.git