Handling Exceptions

默认情况下,如果带注释的侦听器方法抛出异常,它将被抛出到容器中,并且根据容器和代理配置,消息将重新排队并重新发送、丢弃或路由到无效字母交换。没有任何东西返回给发送方。

By default, if an annotated listener method throws an exception, it is thrown to the container and the message are requeued and redelivered, discarded, or routed to a dead letter exchange, depending on the container and broker configuration. Nothing is returned to the sender.

从版本 2.0 开始,@RabbitListener`注解有两个新属性:`errorHandler`和`returnExceptions

Starting with version 2.0, the @RabbitListener annotation has two new attributes: errorHandler and returnExceptions.

它们在默认情况下未配置。

These are not configured by default.

你可以使用`errorHandler`来提供`RabbitListenerErrorHandler`实现的 Bean 名称。此函数接口有一个方法,如下所示:

You can use the errorHandler to provide the bean name of a RabbitListenerErrorHandler implementation. This functional interface has one method, as follows:

@FunctionalInterface
public interface RabbitListenerErrorHandler {

    Object handleError(Message amqpMessage, org.springframework.messaging.Message<?> message,
              ListenerExecutionFailedException exception) throws Exception;

}

如你所见,你可以访问从容器接收到的原始消息、消息转换器生成的 Spring 消息传递`Message<?>`对象以及侦听器抛出的异常(包装在`ListenerExecutionFailedException`中)。错误处理程序可以返回一些结果(作为回复发送)或抛出原始异常或新异常(根据`returnExceptions`设置抛出到容器或返回给发送者)。

As you can see, you have access to the raw message received from the container, the spring-messaging Message<?> object produced by the message converter, and the exception that was thrown by the listener (wrapped in a ListenerExecutionFailedException). The error handler can either return some result (which is sent as the reply) or throw the original or a new exception (which is thrown to the container or returned to the sender, depending on the returnExceptions setting).

当`returnExceptions`属性为`true`时,将导致异常返回给发送者。异常包装在一个`RemoteInvocationResult`对象中。在发送者侧,有一个可用的`RemoteInvocationAwareMessageConverterAdapter`,如果配置到`RabbitTemplate`中,它会重新抛出服务器端异常,并将其包装在`AmqpRemoteException`中。服务器异常的堆栈跟踪是通过合并服务器和客户端堆栈跟踪来合成的。

The returnExceptions attribute, when true, causes exceptions to be returned to the sender. The exception is wrapped in a RemoteInvocationResult object. On the sender side, there is an available RemoteInvocationAwareMessageConverterAdapter, which, if configured into the RabbitTemplate, re-throws the server-side exception, wrapped in an AmqpRemoteException. The stack trace of the server exception is synthesized by merging the server and client stack traces.

此机制通常仅适用于使用 Java 序列化的默认 SimpleMessageConverter。通常,异常不是 “Jackson-friendly”,并且无法序列化为 JSON。如果你使用 JSON,请考虑使用 errorHandler 来在抛出异常时返回其他 Jackson 友好的 Error 对象。

This mechanism generally works only with the default SimpleMessageConverter, which uses Java serialization. Exceptions are generally not “Jackson-friendly” and cannot be serialized to JSON. If you use JSON, consider using an errorHandler to return some other Jackson-friendly Error object when an exception is thrown.

在版本 2.1 中,此接口已从包 o.s.amqp.rabbit.listener 移至 o.s.amqp.rabbit.listener.api

In version 2.1, this interface moved from package o.s.amqp.rabbit.listener to o.s.amqp.rabbit.listener.api.

从版本 2.1.7 开始,`Channel`可以在消息传递消息头中找到;这允许你在使用`AcknowledgeMode.MANUAL`时确认或拒绝失败的消息:

Starting with version 2.1.7, the Channel is available in a messaging message header; this allows you to ack or nack the failed messasge when using 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`。这允许应用程序向调用者发送一些结果,表示收到了格式错误的消息。以前,此类错误是由容器抛出并处理的。

Starting with version 2.2.18, if a message conversion exception is thrown, the error handler will be called, with null in the message argument. This allows the application to send some result to the caller, indicating that a badly-formed message was received. Previously, such errors were thrown and handled by the container.