错误处理
正如本手册开头 概述 中所述,Spring Integration 这种面向消息的框架的主要动机之一是促进组件之间的松散耦合。消息通道在此过程中扮演着重要角色,因为它使得生产者和消费者无需相互了解。然而,优点也伴随着一些缺点。在松散耦合的环境中,有些事情变得更加复杂,错误处理就是一个例子。
当向通道发送消息时,最终处理该消息的组件可能与发送者在同一线程中运行,也可能不在。如果使用简单的默认 DirectChannel
(当 <channel>
元素没有 <queue>
子元素且没有 'task-executor' 属性时),消息处理发生在发送初始消息的同一线程中。在这种情况下,如果抛出 Exception
,它可以被发送者捕获,或者如果它是未捕获的 RuntimeException
,它可能会传播到发送者之外。这与普通 Java 调用堆栈中抛出异常的操作行为相同。
运行在调用者线程上的消息流可以通过消息网关(参见 消息网关)或 MessagingTemplate
(参见 MessagingTemplate
)来调用。在这两种情况下,默认行为都是将任何异常抛给调用者。对于消息网关,请参见 错误处理 以获取有关异常如何抛出以及如何配置网关将错误路由到错误通道的详细信息。当使用 MessagingTemplate
或直接发送到 MessageChannel
时,异常总是抛给调用者。
当添加异步处理时,事情变得更加复杂。例如,如果 'channel' 元素确实提供了 'queue' 子元素(Java 和注解配置中的 QueueChannel
),则处理消息的组件在与发送者不同的线程中运行。当使用 ExecutorChannel
时也是如此。发送者可能已将 Message
放入通道并继续处理其他事情。通过使用标准的 Exception
抛出技术,无法将 Exception
直接抛回给该发送者。相反,处理异步进程的错误需要错误处理机制也是异步的。
Spring Integration 通过将错误发布到消息通道来支持其组件的错误处理。具体来说,Exception
成为 Spring Integration ErrorMessage
的负载。然后,该 Message
被发送到一个消息通道,其解析方式类似于 'replyChannel' 的解析方式。首先,如果发生 Exception
时正在处理的请求 Message
包含 'errorChannel' 消息头(消息头名称在 MessageHeaders.ERROR_CHANNEL
常量中定义),则 ErrorMessage
将发送到该通道。否则,错误处理程序将发送到一个 bean 名称为 errorChannel
的“全局”通道(这也定义为一个常量:IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME
)。
框架内部会创建一个默认的 errorChannel
bean。但是,如果您想控制设置,可以定义自己的。以下示例展示了如何在 XML 配置中定义一个由容量为 500
的队列支持的错误通道:
-
Java
-
XML
@Bean
QueueChannel errorChannel() {
return new QueueChannel(500);
}
<int:channel id="errorChannel">
<int:queue capacity="500"/>
</int:channel>
默认的错误通道是一个 |
这里最重要的一点是,基于消息的错误处理仅适用于由在 TaskExecutor
中执行的 Spring Integration 任务抛出的异常。这不适用于由与发送者在同一线程中运行的处理程序(例如,通过本节前面描述的 DirectChannel
)抛出的异常。
当调度轮询器任务执行中发生异常时,这些异常也会被封装在 |
要启用全局错误处理,请在该通道上注册一个处理程序。例如,您可以将 Spring Integration 的 ErrorMessageExceptionTypeRouter
配置为订阅 errorChannel
的端点的处理程序。该路由器可以根据 Exception
类型将错误消息分发到多个通道。
从版本 4.3.10 开始,Spring Integration 提供了 ErrorMessagePublisher
和 ErrorMessageStrategy
。您可以将它们用作发布 ErrorMessage
实例的通用机制。您可以在任何错误处理场景中调用或扩展它们。ErrorMessageSendingRecoverer
扩展了此类别,作为 RecoveryCallback
实现,可与重试一起使用,例如 RequestHandlerRetryAdvice
。ErrorMessageStrategy
用于根据提供的异常和 AttributeAccessor
上下文构建 ErrorMessage
。它可以注入到任何 MessageProducerSupport
或 MessagingGatewaySupport
中。requestMessage
存储在 AttributeAccessor
上下文的 ErrorMessageUtils.INPUT_MESSAGE_CONTEXT_KEY
下。ErrorMessageStrategy
可以使用该 requestMessage
作为其创建的 ErrorMessage
的 originalMessage
属性。DefaultErrorMessageStrategy
正是这样做的。
从版本 5.2 开始,框架组件抛出的所有 MessageHandlingException
实例都包含一个组件 BeanDefinition
资源和源,以确定异常的配置点。在 XML 配置中,资源是 XML 文件路径,源是带有其 id
属性的 XML 标签。对于 Java 和注解配置,资源是 @Configuration
类,源是 @Bean
方法。在大多数情况下,目标集成流解决方案基于开箱即用的组件及其配置选项。当运行时发生异常时,堆栈跟踪中不涉及任何终端用户代码,因为执行是针对 bean 而不是它们的配置。包含 bean 定义的资源和源有助于确定可能的配置错误并提供更好的开发体验。
从版本 5.4.3 开始,默认错误通道配置了属性 requireSubscribers = true
,以便在通道没有订阅者时(例如,当应用程序上下文停止时)不会默默地忽略消息。在这种情况下,会抛出 MessageDispatchingException
,这可能会导致入站通道适配器的客户端回调对源系统中的原始消息进行否定确认(或回滚),以进行重新传递或其他将来的考虑。要恢复以前的行为(忽略未分发的错误消息),必须将全局集成属性 spring.integration.channels.error.requireSubscribers
设置为 false
。有关更多信息,请参见 全局属性 和 PublishSubscribeChannel
配置(如果您手动配置全局 errorChannel
)。
另请参见 错误处理示例 以获取更多信息。