处理异常
默认情况下,如果带注解的监听器方法抛出异常,异常会被抛给容器,并且消息会根据容器和代理的配置进行重新排队和重新投递、丢弃或路由到死信交换器。不会向发送者返回任何内容。
从版本 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 可以在消息头中获取;这允许你在使用 AcknowledgeMode.MANUAL 时确认或拒绝失败的消息:
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。这允许应用程序向调用方发送一些结果,表明收到了格式错误的消息。在此之前,此类错误会被抛出并由容器处理。