异常处理

默认情况下,如果一个带注解的监听器方法抛出异常,该异常会被抛给容器,消息会根据容器和代理的配置被重新排队、重新投递、丢弃或路由到死信交换机。不会有任何内容返回给发送方。

从 2.0 版本开始,@RabbitListener 注解新增了两个属性:errorHandlerreturnExceptions

这些属性默认未配置。

你可以使用 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 中。服务器异常的堆栈跟踪是通过合并服务器和客户端的堆栈跟踪来合成的。

此机制通常仅适用于使用 Java 序列化的默认 SimpleMessageConverter。异常通常不是“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。这允许应用程序向调用者发送一些结果,表明收到了格式错误的消息。此前,此类错误会被抛出并由容器处理。