错误处理

正如本手册开头的概述中所述,面向消息的框架(如 Spring Integration)背后的主要动机之一是促进组件之间的松耦合。 消息通道起着重要作用,因为生成者和使用者不必相互了解。 但是,这些优点也有一些缺点。 在松散耦合的环境中,有些事情会变得更加复杂,错误处理就是一个例子。spring-doc.cn

当向通道发送消息时,最终处理该消息的组件可能与发送者在同一个线程中运行,也可能不在运行。 如果使用简单的默认值(当元素没有子元素且没有 'task-executor' 属性时),则消息处理发生在发送初始消息的同一线程中。 在这种情况下,如果抛出 an,则发件人可以捕获它,或者如果它是未捕获的 . 这与普通 Java 调用堆栈中的异常引发操作的行为相同。DirectChannel<channel><queue>ExceptionRuntimeExceptionspring-doc.cn

在调用方线程上运行的消息流可以通过消息传递网关(请参阅 Messaging Gateways)或 (请参阅 MessagingTemplate)调用。 在任何一种情况下,默认行为都是向调用方引发任何异常。 对于消息传递网关,请参阅错误处理,了解有关如何引发异常以及如何配置网关以将错误路由到错误通道的详细信息。 当使用 a 或 直接发送到 a 时,总是会向调用方抛出异常。MessagingTemplateMessagingTemplateMessageChannelspring-doc.cn

添加异步处理时,事情会变得更加复杂。 例如,如果'channel'元素确实提供了一个'queue'子元素(在Java和注释配置中,那么处理消息的组件将在与发送者不同的线程中运行。 使用 an 时也是如此。 发送者可能已经将 放入通道并继续处理其他事情。 无法使用标准引发技术将 直接抛回到该发送者。 相反,处理异步进程的错误要求错误处理机制也是异步的。QueueChannelExecutorChannelMessageExceptionExceptionspring-doc.cn

Spring 集成通过将错误发布到消息通道来支持对其组件进行错误处理。 具体来说,它成为 Spring Integration 的有效负载。 然后将其发送到消息通道,该通道以类似于 'replyChannel' 解析的方式进行解析。 首先,如果在发生时正在处理的请求包含一个 'errorChannel' 头(头名称在常量中定义),则会将其发送到该通道。 否则,错误处理程序将发送到 bean 名称为 (这也定义为常量: 的“全局”通道)。ExceptionErrorMessageMessageMessageExceptionMessageHeaders.ERROR_CHANNELErrorMessageerrorChannelIntegrationContextUtils.ERROR_CHANNEL_BEAN_NAMEspring-doc.cn

默认 Bean 由 Framework 在内部创建。 但是,如果要控制设置,您可以定义自己的设置。 以下示例显示如何在XML配置中定义错误通道,该配置由容量为 :errorChannel500spring-doc.cn

@Bean
QueueChannel errorChannel() {
    return new QueueChannel(500);
}
<int:channel id="errorChannel">
    <int:queue capacity="500"/>
</int:channel>
默认错误通道是 . 默认情况下,它具有 作为订阅者,其日志记录级别和订阅顺序为 。 如果您订阅其他使用终端节点,这可能会引发异常,并且您不想抢占日志记录,请确保其他处理程序具有更高的顺序。PublishSubscribeChannelLoggingHandlerERROROrdered.LOWEST_PRECEDENCE - 100

这里要了解的最重要的一点是,基于消息传递的错误处理仅适用于在 . 这不适用于在与发送方相同的线程中运行的处理程序引发的异常(例如,通过本节前面所述的 a)。TaskExecutorDirectChannelspring-doc.cn

当计划的 Poller 任务执行中发生异常时,这些异常被包装在实例中,并发送到'errorChannel'。 这是通过注入到全局 bean 中来完成的。 如果仍必须使用标准 'errorChannel' 集成流逻辑完成错误处理,则建议将其用于任何自定义。 在这种情况下,可以使用已注册的 Bean。ErrorMessageMessagePublishingErrorHandlertaskSchedulerMessagePublishingErrorHandlertaskSchedulerintegrationMessagePublishingErrorHandler

要启用全局错误处理,请在该通道上注册处理程序。 例如,您可以将 Spring Integration 配置为订阅了 . 然后,该路由器可以根据类型将错误消息传播到多个通道。ErrorMessageExceptionTypeRoutererrorChannelExceptionspring-doc.cn

从版本 4.3.10 开始, Spring 集成提供了 和 . 您可以将它们用作发布实例的通用机制。 您可以在任何错误处理场景中调用或扩展它们。 它将此类扩展为可与重试一起使用的实现,例如 RequestHandlerRetryAdvice。 这用于基于提供的异常和上下文构建一个。 它可以注射到任何 或 中。 存储在 context. 它可以将其用作它创建的属性。 这正是这样做的。ErrorMessagePublisherErrorMessageStrategyErrorMessageErrorMessageSendingRecovererRecoveryCallbackErrorMessageStrategyErrorMessageAttributeAccessorMessageProducerSupportMessagingGatewaySupportrequestMessageErrorMessageUtils.INPUT_MESSAGE_CONTEXT_KEYAttributeAccessorErrorMessageStrategyrequestMessageoriginalMessageErrorMessageDefaultErrorMessageStrategyspring-doc.cn

从版本 5.2 开始,框架组件抛出的所有实例都包括组件资源和源,用于确定异常的配置点。 在 XML 配置的情况下,资源是 XML 文件路径,并使用其属性源 XML 标记。 在Java和注释配置中,资源是一个类,源是一个方法。 在大多数情况下,目标集成流解决方案基于开箱即用的组件及其配置选项。 当运行时发生异常时,堆栈跟踪中不涉及任何最终用户代码,因为执行是针对 Bean,而不是它们的配置。 包括 Bean 定义的资源和源有助于确定可能的配置错误,并提供更好的开发人员体验。MessageHandlingExceptionBeanDefinitionid@Configuration@Beanspring-doc.cn

从版本 5.4.3 开始,默认错误通道配置了属性,当此通道上没有订阅者时(例如,当应用程序上下文停止时),不会静默忽略消息。 在这种情况下,会抛出 a,这可能会在入站通道适配器的客户端回调上对源系统中的原始消息进行否定确认(或回滚),以便重新传递或将来考虑其他情况。 要恢复以前的行为(忽略未调度的错误消息),必须将全局集成属性设置为 。 有关更多信息,请参阅全局属性PublishSubscribeChannel 配置(如果手动配置全局)。requireSubscribers = trueMessageDispatchingExceptionspring.integration.channels.error.requireSubscribersfalseerrorChannelspring-doc.cn

有关更多信息,另请参阅 错误处理示例spring-doc.cn