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", "RobertoHuang@foxmail.com");
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异常处理