Error Handling
如本手册最开始 overview 所述,Spring 集成等面向消息的框架背后的一个主要动机是促进组件之间的松散耦合。消息信道扮演着重要角色,因为生产者和消费者不必互相了解。但是,这些优点也有一些缺点。在松散耦合的环境中,某些事情会变得更加复杂,错误处理就是其中一个示例。
As described in the overview at the very beginning of this manual, one of the main motivations behind a message-oriented framework such as Spring Integration is to promote loose coupling between components. The message channel plays an important role, in that producers and consumers do not have to know about each other. However, the advantages also have some drawbacks. Some things become more complicated in a loosely coupled environment, and one example is error handling.
向通道发送消息时,最终处理该消息的组件可能与发送者在同一线程内运行,也可能不在同一线程内运行。如果使用简单的默认 DirectChannel
(其中 <channel>
元素没有 <queue>
子元素,也没有 task-executor
属性),则消息处理发生在发送初始消息的同一线程中。在这种情况下,如果抛出一个 Exception
,它可以被发送者捕获,或者如果它是一个未捕获的 RuntimeException
,则它可能传播到发送者之外。这与正常 Java 调用堆栈中抛出异常的操作相同。
When sending a message to a channel, the component that ultimately handles that message may or may not be operating within the same thread as the sender.
If using a simple default DirectChannel
(when the <channel>
element that has no <queue>
child element and no 'task-executor' attribute), the message handling occurs in the same thread that sends the initial message.
In that case, if an Exception
is thrown, it can be caught by the sender, or it may propagate past the sender if it is an uncaught RuntimeException
.
This is the same behavior as an exception-throwing operation in a normal Java call stack.
通过消息网关(参见 Messaging Gateways)或 MessagingTemplate
(参见 MessagingTemplate
)可以调用在调用方线程中运行的消息流。在任一情况下,默认行为是向调用方抛出任何异常。对于消息网关,请参阅 Error Handling,了解有关如何抛出异常以及如何配置该网关以将错误路由到错误信道的信息。在使用 MessagingTemplate
或直接发送到 MessageChannel
时,异常始终会抛给调用方。
A message flow that runs on a caller thread might be invoked through a messaging gateway (see Messaging Gateways) or a MessagingTemplate
(see MessagingTemplate
).
In either case, the default behavior is to throw any exceptions to the caller.
For the messaging gateway, see Error Handling for details about how the exception is thrown and how to configure the gateway to route the errors to an error channel instead.
When using a MessagingTemplate
or sending to a MessageChannel
directly, exceptions are always thrown to the caller.
添加异步处理后,事情变得更加复杂。例如,如果 channel
元素确实提供了一个 queue
子元素(Java 和注释配置中的 QueueChannel
),那么处理消息的组件在与发送器不同的线程中运行。使用 ExecutorChannel
时也是如此。发送者可能已将 Message
放入通道并转到其他事情。Exception
无法使用标准 Exception
抛出技术直接抛回该发送者。相反,处理异步进程的错误要求错误处理机制也是异步的。
When adding asynchronous processing, things become rather more complicated.
For instance, if the 'channel' element does provide a 'queue' child element (QueueChannel
in Java & Annotations Configuration), the component that handles the message operates in a different thread than the sender.
The same is true when an ExecutorChannel
is used.
The sender may have dropped the Message
into the channel and moved on to other things.
There is no way for the Exception
to be thrown directly back to that sender by using standard Exception
throwing techniques.
Instead, handling errors for asynchronous processes requires that the error-handling mechanism also be asynchronous.
Spring Integration 通过将错误发布到消息通道来支持对其组件的错误处理。具体来说,Exception
成为 Spring Integration ErrorMessage
的有效负载。然后将 Message
发送到以类似于 replyChannel
解析的方式解析的消息通道。首先,如果在发生 Exception
时正在处理的请求 Message
具有 errorChannel
标头(标头名称在 MessageHeaders.ERROR_CHANNEL
常量中定义),则 ErrorMessage
将发送到该通道。否则,错误处理程序将发送到 bean 名称为 errorChannel
的“全局”通道(这也定义为一个常量:IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME
)。
Spring Integration supports error handling for its components by publishing errors to a message channel.
Specifically, the Exception
becomes the payload of a Spring Integration ErrorMessage
.
That Message
is then sent to a message channel that is resolved in a way that is similar to the 'replyChannel' resolution.
First, if the request Message
being handled at the time the Exception
occurred contains an 'errorChannel' header (the header name is defined in the MessageHeaders.ERROR_CHANNEL
constant), the ErrorMessage
is sent to that channel.
Otherwise, the error handler sends to a “global” channel whose bean name is errorChannel
(this is also defined as a constant: IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME
).
框架在内部创建一个默认的 errorChannel
bean。然而,如果你希望控制设置,你可以定义你自己的 errorChannel
。以下示例显示如何在由具有容量为 500
的队列做后盾的 XML 配置中定义错误通道:
A default errorChannel
bean is created internally by the Framework.
However, you can define your own if you want to control the settings.
The following example shows how to define an error channel in XML configuration backed by a queue with a capacity of 500
:
-
Java
-
XML
@Bean
QueueChannel errorChannel() {
return new QueueChannel(500);
}
<int:channel id="errorChannel">
<int:queue capacity="500"/>
</int:channel>
默认的错误通道是 |
The default error channel is a |
这里要理解的最重要的事情是,基于消息的错误处理仅适用于由在 TaskExecutor
内执行的 Spring Integration 任务抛出的异常。这并不适用于在与发送者同一线程内操作的处理程序抛出的异常(例如,如本节前面所述,通过 DirectChannel
)。
The most important thing to understand here is that the messaging-based error handling applies only to exceptions that are thrown by a Spring Integration task that is executing within a TaskExecutor
.
This does not apply to exceptions thrown by a handler that operates within the same thread as the sender (for example, through a DirectChannel
as described earlier in this section).
当计划的轮询任务执行中发生异常时,这些异常会封装在 |
When exceptions occur in a scheduled poller task’s execution, those exceptions are wrapped in |
要启用全局错误处理,请在该通道上注册一个处理程序。例如,你可以将 Spring Integration 的 ErrorMessageExceptionTypeRouter
配置为订阅 errorChannel
的端点的处理程序。然后,根据 Exception
类型,该路由器可以将错误消息分散到多个通道。
To enable global error handling, register a handler on that channel.
For example, you can configure Spring Integration’s ErrorMessageExceptionTypeRouter
as the handler of an endpoint that is subscribed to the errorChannel
.
That router can then spread the error messages across multiple channels, based on the Exception
type.
从版本 4.3.10 开始,Spring 集成提供 ErrorMessagePublisher
和 ErrorMessageStrategy
。您可以将它们用作发布 ErrorMessage
实例的一般机制。您可以在任何错误处理场景中调用或扩展它们。ErrorMessageSendingRecoverer
将此类扩展为可用于重试的 RecoveryCallback
实现,例如 RequestHandlerRetryAdvice
。ErrorMessageStrategy
用于根据提供的异常和 AttributeAccessor
上下文构建 ErrorMessage
。它可以注入到任何 MessageProducerSupport
或 MessagingGatewaySupport
中。requestMessage
储存在 AttributeAccessor
上下文中的 ErrorMessageUtils.INPUT_MESSAGE_CONTEXT_KEY
下。ErrorMessageStrategy
可以使用该 requestMessage
作为其创建的 ErrorMessage
的 originalMessage
属性。DefaultErrorMessageStrategy
正好就是这样做的。
Starting with version 4.3.10, Spring Integration provides the ErrorMessagePublisher
and the ErrorMessageStrategy
.
You can use them as a general mechanism for publishing ErrorMessage
instances.
You can call or extend them in any error handling scenarios.
The ErrorMessageSendingRecoverer
extends this class as a RecoveryCallback
implementation that can be used with retry, such as the
RequestHandlerRetryAdvice
.
The ErrorMessageStrategy
is used to build an ErrorMessage
based on the provided exception and an AttributeAccessor
context.
It can be injected into any MessageProducerSupport
or MessagingGatewaySupport
.
The requestMessage
is stored under ErrorMessageUtils.INPUT_MESSAGE_CONTEXT_KEY
in the AttributeAccessor
context.
The ErrorMessageStrategy
can use that requestMessage
as the originalMessage
property of the ErrorMessage
it creates.
The DefaultErrorMessageStrategy
does exactly that.
从 5.2 版开始,框架组件抛出的所有 MessageHandlingException
实例都包含一个组件 BeanDefinition
资源和源来确定配置点以形成异常。在 XML 配置中,资源是 XML 文件路径和带其 id
属性的 XML 标记。在使用 Java 和注释的配置中,资源是一个 @Configuration
类和源是一个 @Bean
方法。在大多数情况下,目标集成流程解决方案基于开箱即用的组件及其配置选项。当在运行时发生异常时,由于执行针对 bean,而不是 bean 的配置,因此堆栈跟踪中不包含任何最终用户代码。包含 bean 定义的资源和源有助于确定可能的配置错误,并提供更好的开发人员体验。
Starting with version 5.2, all the MessageHandlingException
instances thrown by the framework components, includes a component BeanDefinition
resource and source to determine a configuration point form the exception.
In case of XML configuration, a resource is an XML file path and source an XML tag with its id
attribute.
With Java & Annotation configuration, a resource is a @Configuration
class and source is a @Bean
method.
In most case the target integration flow solution is based on the out-of-the-box components and their configuration options.
When an exception happens at runtime, there is no any end-user code involved in stack trace because an execution is against beans, not their configuration.
Including a resource and source of the bean definition helps to determine possible configuration mistakes and provides better developer experience.
从版本 5.4.3 开始,默认错误信道配置了属性 requireSubscribers = true
,以便在该信道上没有订阅者时不静默忽略消息(例如,当应用程序上下文已停止时)。在这种情况下,将抛出一个 MessageDispatchingException
,该异常可能会借用入站信道适配器的客户端回调函数,以否定确认(或回滚)源系统中的原始消息,以便重新传递或将来考虑。要恢复之前的行为(忽略未分派错误消息),则必须将全局集成属性 spring.integration.channels.error.requireSubscribers
设置为 false
。有关详细信息,请参见 Global Properties 和 PublishSubscribeChannel
Configuration(如果您手动配置全局 errorChannel
)。
Starting with version 5.4.3, the default error channel is configured with the property requireSubscribers = true
to not silently ignore messages when there are no subscribers on this channel (e.g. when application context is stopped).
In this case a MessageDispatchingException
is thrown which may lend on the client callback of the inbound channel adapter to negatively acknowledge (or roll back) an original message in the source system for redelivery or other future consideration.
To restore the previous behavior (ignore non-dispatched error messages), the global integration property spring.integration.channels.error.requireSubscribers
must be set to false
.
See Global Properties and PublishSubscribeChannel
Configuration (if you configure a global errorChannel
manually) for more information.
另请参阅 Error Handling Sample 了解更多信息。
See also Error Handling Sample for more information.