(五) RabbitMQ实战教程(面向Java开发人员)之RabbitMQ异常处理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/RobertoHuang/article/details/79597343

RabbitMQ异常处理

使用JAVA客户端整合RabbitMQ进行的许多操作都会抛出异常,我们可以自定义异常处理器进行处理,比如我们希望在RabbitMQ消费消息失败时记录一条日志,又或者在消息消费失败时发送一则通知等操作

本系列博客源码GIT地址:https://github.com/RobertoHuang/RGP-RABBITMQ.git

RabbitMQ Java Client

1.创建连接工具类 并设置异常处理器

public class ChannelUtils {
    public static Channel getChannelInstance(String connectionDescription) {
        try {
            ConnectionFactory connectionFactory = getConnectionFactory();
            Connection connection = connectionFactory.newConnection(connectionDescription);
            return connection.createChannel();
        } catch (Exception e) {
            throw new RuntimeException("获取Channel连接失败");
        }
    }

    private static ConnectionFactory getConnectionFactory() {
        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("192.168.56.128");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setUsername("roberto");
        connectionFactory.setPassword("roberto");

        connectionFactory.setAutomaticRecoveryEnabled(true);
        connectionFactory.setNetworkRecoveryInterval(10000);

        Map<String, Object> connectionFactoryPropertiesMap = new HashMap();
        connectionFactoryPropertiesMap.put("principal", "RobertoHuang");
        connectionFactoryPropertiesMap.put("description", "RGP订单系统V2.0");
        connectionFactoryPropertiesMap.put("emailAddress", "[email protected]");
        connectionFactory.setClientProperties(connectionFactoryPropertiesMap);

        // 设置自定义异常处理器
        connectionFactory.setExceptionHandler(new DefaultExceptionHandler() {
            @Override
            public void handleConsumerException(Channel channel, Throwable exception, Consumer consumer, String consumerTag, String methodName) {
                System.out.println("----------消息消费异常处理----------");
                System.out.println("消息消费异常日志记录:" + exception.getMessage());
                super.handleConsumerException(channel, exception, consumer, consumerTag, methodName);
            }
        });
        return connectionFactory;
    }
}

2.创建消息生产者

public class MessageProducer {
    public static void main(String[] args) throws IOException, TimeoutException {
        Channel channel = ChannelUtils.getChannelInstance("RGP订单系统消息生产者");

        channel.exchangeDeclare("roberto.order", BuiltinExchangeType.DIRECT, true, false, false,new HashMap<>());

        AMQP.BasicProperties basicProperties = new AMQP.BasicProperties().builder().deliveryMode(2).contentType("UTF-8").build();
        channel.basicPublish("roberto.order", "add", false, basicProperties, "订单信息".getBytes());
    }
}

3.创建消费者 在进行消息消费时我们手动抛出了一个异常

public class MessageConsumer {
    public static void main(String[] args) throws IOException, TimeoutException {
        Channel channel = ChannelUtils.getChannelInstance("RGP订单系统消息消费者");

        AMQP.Queue.DeclareOk declareOk = channel.queueDeclare("roberto.order.add", true, false, false, new HashMap<>());

        channel.exchangeDeclare("roberto.order", BuiltinExchangeType.DIRECT, true, false, false, new HashMap<>());

        channel.queueBind(declareOk.getQueue(), "roberto.order", "add", new HashMap<>());

        channel.basicConsume(declareOk.getQueue(), true, "RGP订单系统ADD处理逻辑消费者", new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println(consumerTag);
                System.out.println(envelope.toString());
                System.out.println(properties.toString());
                System.out.println("消息内容:" + new String(body));
                throw new RuntimeException("添加订单消息消费出现异常");
            }
        });
    }
}

4.依次启动消息消费者和生产者 控制台输出如下

RGP订单系统ADD处理逻辑消费者
Envelope(deliveryTag=1, redeliver=false, exchange=roberto.order, routingKey=add)
#contentHeader<basic>(content-type=UTF-8, content-encoding=null, headers=null, delivery-mode=2, 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)
消息内容:订单信息
----------消息消费异常处理----------
消息消费异常日志记录:添加订单消息消费出现异常

说明当消费消息出现异常时,会进入我们自定义异常处理的逻辑。需要注意的是默认RabbitMQ Java Client在发生异常时会将Channel/Connection关闭,进而使程序未能按照预期的方向执行,所以我们在软件设计的时候应当考虑周全

Spring AMQP配置方式

Spring AMQP在监听器抛出一个异常的时候它会将该异常包装成ListenerExecutionFailedException,通常这个消息会被拒绝并且重新放入队列中,如果设置DefaultRequeueRejected属性为false将把这个消息直接丢弃。需要注意的是如果抛出的异常是 ARADRE 或其他被RabbitMQ认为是致命错误的异常,即便DefaultRequeueRejected的值为true该消息也不会重新加入队列,而是会被直接丢弃。当抛出异常为以下几种异常时消息将不会重新入队列

1.org.springframework.amqp.support.converter.MessageConversionException
2.org.springframework.messaging.converter.MessageConversionException
3.org.springframework.messaging.handler.invocation.MethodArgumentResolutionException
4.java.lang.NoSuchMethodException
5.java.lang.ClassCastException

关于Spring AMQP异常处理可参见博客:Spring AMQP异常处理

猜你喜欢

转载自blog.csdn.net/RobertoHuang/article/details/79597343