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