如需使用最新稳定版本,请使用 Spring Integration 7.0.4spring-doc.cadn.net.cn

错误处理

正如本手册开头概述中所描述的那样,像 Spring Integration 这样的面向消息框架的主要动机之一是促进组件之间的松耦合。 消息通道扮演着重要角色,因为生产者和消费者无需彼此知晓。 然而,这些优势也带来了一些缺点。 在松耦合环境中,某些事情会变得更加复杂,例如错误处理就是一个例子。spring-doc.cadn.net.cn

当向通道发送消息时,最终处理该消息的组件可能在与发送者相同的线程中运行,也可能不在。 如果使用简单的默认值 DirectChannel(即当 <channel> 元素没有 <queue> 子元素且没有 'task-executor' 属性时),消息处理将在发送初始消息的同一线程中进行。 在这种情况下,如果抛出 Exception,它可能被发送者捕获;如果它是未捕获的 RuntimeException,则可能会传播到发送者之外。 这与正常 Java 调用堆栈中抛出异常的操作行为相同。spring-doc.cadn.net.cn

在调用者线程上运行的消息流可以通过消息网关(参见 消息网关)或 MessagingTemplate(参见 MessagingTemplate)来触发。 在这两种情况下,默认行为是将任何异常抛回给调用者。 对于消息网关,有关如何抛出异常的详细信息以及如何配置网关将错误路由到错误通道,请参见 错误处理。 当使用 MessagingTemplate 或直接发送到 MessageChannel 时,异常始终会抛回给调用者。spring-doc.cadn.net.cn

当添加异步处理时,事情会变得相当复杂。 例如,如果"channel"元素确实提供了一个"queue"子元素(在 Java & Annotations 配置中为QueueChannel),则处理消息的组件将在与发送者不同的线程中运行。 使用ExecutorChannel时也是如此。 发送者可能已将Message放入通道并继续处理其他任务。 无法通过标准的Exception抛出技术将异常直接抛回给该发送者。 相反,处理异步过程的错误需要错误处理机制本身也是异步的。spring-doc.cadn.net.cn

Spring Integration 支持通过向消息通道发布错误来处理其组件的错误。 具体来说,Exception 成为 Spring Integration ErrorMessage 的有效负载(payload)。 随后,该 Message 被发送到消息通道,其解析方式类似于 'replyChannel' 的解析方式。 首先,如果在发生 Exception 时正在处理的请求 Message 包含名为 'errorChannel' 的头部(该头部名称在 MessageHeaders.ERROR_CHANNEL 常量中定义),则 ErrorMessage 将被发送到该通道。 否则,错误处理器会将错误发送到名为 errorChannel 的“全局”通道(这也定义为常量:IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME)。spring-doc.cadn.net.cn

框架内部会自动创建一个默认的 errorChannel bean。 不过,如果您希望控制设置,也可以自行定义。 以下示例展示了如何在基于容量为 500 的队列的 XML 配置中定义错误通道:spring-doc.cadn.net.cn

@Bean
QueueChannel errorChannel() {
    return new QueueChannel(500);
}
<int:channel id="errorChannel">
    <int:queue capacity="500"/>
</int:channel>
默认错误通道是一个 PublishSubscribeChannel。 默认情况下,它有一个订阅者,其日志级别为 LoggingHandler,订阅顺序为 Ordered.LOWEST_PRECEDENCE - 100。 如果您订阅了其他可能抛出异常的消费端点,并且不希望预先中断日志记录,请确保这些额外的处理器具有更高的优先级(order)。

这里需要理解的最重要的一点是,基于消息的错误处理仅适用于在 TaskExecutor 内执行 Spring Integration 任务时抛出的异常。 这不适用于由与发送者处于同一线程中运行的处理器所抛出的异常(例如,如本节前面所述,通过 DirectChannel)。spring-doc.cadn.net.cn

当调度轮询任务执行过程中发生异常时,这些异常会被包装在 ErrorMessage 实例中,并发送至 'errorChannel'。 这是通过将 MessagePublishingErrorHandler 注入到全局 taskScheduler Bean 中实现的。 如果错误处理仍需使用标准的 'errorChannel' 集成流逻辑,则建议对该 MessagePublishingErrorHandler 进行任何自定义 taskScheduler。 在此情况下,可以使用已注册的 integrationMessagePublishingErrorHandler Bean。

要启用全局错误处理,请在该通道上注册一个处理器。 例如,您可以将 Spring Integration 的ErrorMessageExceptionTypeRouter配置为订阅了errorChannel的端点的处理器。 该路由器随后可以根据Exception类型将错误消息分发到多个通道。spring-doc.cadn.net.cn

从 4.3.10 版本开始,Spring Integration 提供了 ErrorMessagePublisherErrorMessageStrategy。 您可以将它们用作发布 ErrorMessage 实例的通用机制。 您可以在任何错误处理场景中调用或扩展它们。 ErrorMessageSendingRecoverer 扩展了此类,作为可重试的 RecoveryCallback 实现,例如 RequestHandlerRetryAdviceErrorMessageStrategy 用于基于提供的异常和 AttributeAccessor 上下文构建 ErrorMessage。 它可以注入到任何 MessageProducerSupportMessagingGatewaySupport 中。 requestMessage 存储在 AttributeAccessor 上下文中的 ErrorMessageUtils.INPUT_MESSAGE_CONTEXT_KEY 下。 ErrorMessageStrategy 可以使用该 requestMessage 作为其创建的 ErrorMessageoriginalMessage 属性。 DefaultErrorMessageStrategy 正是这样做的。spring-doc.cadn.net.cn

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

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

另请参阅 错误处理示例 以获取更多信息。spring-doc.cadn.net.cn