错误处理

如本手册开头 概述 中所述,像 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 将发送到该通道。否则,错误处理器将发送到名为 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>
默认错误通道是 PublishSubscribeChannel。默认情况下,它有一个 LoggingHandler 作为订阅者,其日志级别为 ERROR,订阅顺序为 Ordered.LOWEST_PRECEDENCE - 100。如果您订阅了可能抛出异常的额外消费端点,并且您不想抢占日志记录,请确保额外处理器的顺序更高。

这里最重要的是要明白,基于消息的错误处理仅适用于由在 TaskExecutor 中执行的 Spring Integration 任务抛出的异常。这不适用于与发送者在同一线程中操作的处理程序抛出的异常(例如,通过本节前面描述的 DirectChannel)。

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

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

从 4.3.10 版本开始,Spring Integration 提供了 ErrorMessagePublisherErrorMessageStrategy。您可以将它们用作发布 ErrorMessage 实例的通用机制。您可以在任何错误处理场景中调用或扩展它们。ErrorMessageSendingRecoverer 将此类别扩展为 RecoveryCallback 实现,可与重试一起使用,例如 RequestHandlerRetryAdviceErrorMessageStrategy 用于根据提供的异常和 AttributeAccessor 上下文构建 ErrorMessage。它可以注入到任何 MessageProducerSupportMessagingGatewaySupport 中。requestMessage 存储在 AttributeAccessor 上下文中的 ErrorMessageUtils.INPUT_MESSAGE_CONTEXT_KEY 下。ErrorMessageStrategy 可以将该 requestMessage 用作其创建的 ErrorMessageoriginalMessage 属性。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)。

另请参阅 错误处理示例 以获取更多信息。

© . This site is unofficial and not affiliated with VMware.