处理异常
默认情况下,如果被注解的监听方法抛出异常,该异常会被抛给容器,而消息会根据容器和 broker 的配置被重新入队并重新投递、丢弃,或路由到死信交换机。不会向发送方返回任何内容。
从 2.0 版开始,@RabbitListener 注解新增了两个属性:errorHandler 和 returnExceptions。
这两个属性默认不配置。
你可以使用 errorHandler 提供一个 RabbitListenerErrorHandler 实现的 bean 名。这个函数式接口有一个方法,如下所示:
@FunctionalInterface
public interface RabbitListenerErrorHandler {
Object handleError(Message amqpMessage, org.springframework.messaging.Message<?> message,
ListenerExecutionFailedException exception) throws Exception;
}
如你所见,你可以访问从容器接收到的原始消息、由消息转换器产生的 spring-messaging Message<?> 对象,以及监听器抛出的异常(包装在 ListenerExecutionFailedException 中)。错误处理器既可以返回某个结果(作为回复发送),也可以抛出原始异常或新异常(根据 returnExceptions 设置,该异常会被抛给容器或返回给发送方)。
当 returnExceptions 属性为 true 时,会导致异常被返回给发送方。该异常被包装在一个 RemoteInvocationResult 对象中。在发送方一侧,有一个可用的 RemoteInvocationAwareMessageConverterAdapter,如果将其配置到 RabbitTemplate 中,它会重新抛出服务端异常,并包装在 AmqpRemoteException 中。服务端异常的堆栈跟踪是通过合并服务端和客户端的堆栈跟踪而合成的。
这种机制通常只适用于默认的 SimpleMessageConverter,它使用 Java 序列化。异常通常不"对 Jackson 友好",无法序列化为 JSON。如果你使用 JSON,请考虑在抛出异常时使用 errorHandler 返回其他对 Jackson 友好的 Error 对象。
在 2.1 版中,此接口从包 o.s.amqp.rabbit.listener 移到了 o.s.amqp.rabbit.listener.api。
从 2.1.7 版开始,Channel 可在 messaging 消息头中获取;这让你在使用 AcknowledgeMode.MANUAL 时可以对失败的消息进行 ack 或 nack:
public Object handleError(Message amqpMessage, org.springframework.messaging.Message<?> message,
ListenerExecutionFailedException exception) {
...
message.getHeaders().get(AmqpHeaders.CHANNEL, Channel.class)
.basicReject(message.getHeaders().get(AmqpHeaders.DELIVERY_TAG, Long.class),
true);
}
从 2.2.18 版开始,如果抛出消息转换异常,将调用错误处理器,此时 message 参数为 null。这让应用程序可以向调用方发送某个结果,表明接收到了一条格式错误的消息。此前,此类错误会被抛出并由容器处理。