为端点添加行为
在 Spring Integration 2.2 之前,你可以通过向轮询器的 <advice-chain/> 元素添加 AOP 通知来为整个集成流添加行为。然而,假设你只想重试某个 REST Web 服务调用,而不涉及任何下游端点。
例如,考虑以下流程:
inbound-adapter->poller->http-gateway1->http-gateway2->jdbc-outbound-adapter
如果你在轮询器(poller)的advice链中配置了重试逻辑,并且由于网络故障导致对http-gateway2的调用失败,重试机制会导致http-gateway1和http-gateway2都被第二次调用。类似地,当jdbc-outbound-adapter发生瞬时故障后,两个HTTP网关会先被再次调用,然后才重新调用jdbc-outbound-adapter。
Spring Integration 2.2 新增了为单个端点添加行为的功能。这是通过在许多端点中添加 <request-handler-advice-chain/> 元素来实现的。以下示例展示了如何在 outbound-gateway 中使用 <request-handler-advice-chain/> 元素:
<int-http:outbound-gateway id="withAdvice"
url-expression="'http://localhost/test1'"
request-channel="requests"
reply-channel="nextChannel">
<int-http:request-handler-advice-chain>
<ref bean="myRetryAdvice" />
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
在这种情况下,myRetryAdvice 仅应用于此网关的本地范围,不会在回复发送到 nextChannel 后对下游的进一步操作生效。该通知的作用范围仅限于端点本身。
目前,您无法为整个 <chain/> 端点配置建议链。该模式不允许 <request-handler-advice-chain> 作为链本身的子元素。
但是,可以在 <chain> 元素内为各个产生回复的端点添加 <request-handler-advice-chain>。一个例外是,在链中不产生回复的情况下,由于链的最后一个元素是 outbound-channel-adapter,该最后一个元素无法被建议。如果您需要为此类元素配置建议链,必须将其移出链外(链的 output-channel 作为适配器的 input-channel)。然后,适配器可以像往常一样被建议。对于产生回复的链,每个子元素都可以被建议。
章节总结
📄️ 提供的建议类
除了提供应用AOP通知类的通用机制外,Spring Integration还提供了以下开箱即用的通知实现:
📄️ Reactive Advice
从版本5.3开始,ReactiveRequestHandlerAdvice可用于处理生成Mono回复的请求消息处理器。为此,必须提供一个BiFunction\<Message, Publisher\<?>>,该函数会通过Mono.transform()操作符在拦截的handleRequestMessage()方法实现生成的回复中被调用。通常,当我们希望通过timeout()、retry()等支持操作符来控制网络波动时,这种Mono定制是必要的。例如,当我们通过WebFlux客户端发起HTTP请求时,可以使用以下配置来确保等待响应的时间不超过5秒:
📄️ 上下文持有者建议
从版本6.1开始,我们引入了 ContextHolderRequestHandlerAdvice。这个通知会从请求消息中提取某些值,并将其存储在上下文持有器中。当目标 MessageHandler 上的执行完成时,该值会从上下文中清除。理解这个通知的最佳方式类似于编程流程:我们将某个值存储到 ThreadLocal 中,从目标调用中访问它,然后在执行后清理 ThreadLocal。ContextHolderRequestHandlerAdvice 需要以下构造函数参数:一个 Function\<Message\<?>, Object> 作为值提供者,一个 Consumer 作为上下文设置回调,以及一个 Runnable 作为上下文清理钩子。
📄️ 自定义建议类
除了前面描述的建议类之外,您还可以实现自己的建议类。虽然您可以提供 org.aopalliance.aop.Advice(通常是 org.aopalliance.intercept.MethodInterceptor)的任何实现,但我们通常建议您继承 o.s.i.handler.advice.AbstractRequestHandlerAdvice。这样做的好处是避免编写低级的面向切面编程代码,同时提供了一个专门为此环境定制使用的起点。
📄️ 其他建议链元素
虽然上面提到的抽象类是一种便利,但您可以将任何通知(包括事务通知)添加到链中。
📄️ 处理消息建议
正如本节引言所述,请求处理器通知链中的通知对象仅应用于当前端点,而非下游流程(如果存在)。对于生成回复的 MessageHandler 对象(例如扩展 AbstractReplyProducingMessageHandler 的处理器),通知将应用于内部方法:handleRequestMessage()(从 MessageHandler.handleMessage() 调用)。对于其他消息处理器,通知将应用于 MessageHandler.handleMessage()。
📄️ 事务支持
从版本 5.0 开始,通过 HandleMessageAdvice 实现,引入了一个新的 TransactionHandleMessageAdvice,以使整个下游流程具有事务性。当在 \<request-handler-advice-chain> 元素中使用常规的 TransactionInterceptor 时(例如,通过配置 \<tx:advice>),启动的事务仅适用于内部的 AbstractReplyProducingMessageHandler.handleRequestMessage(),而不会传播到下游流程。
📄️ 建议过滤器
在配置过滤器建议时还有一个额外注意事项。默认情况下,任何丢弃操作(当过滤器返回 false 时)都会在建议链的作用域内执行。这可能包括丢弃通道下游的所有流程。例如,如果丢弃通道下游的某个元素抛出异常且存在重试建议,则流程会被重试。同样,如果 throwExceptionOnRejection 设置为 true(异常会在建议作用域内抛出)。
📄️ 使用注解建议端点
在使用注解(@Filter、@ServiceActivator、@Splitter 和 @Transformer)配置某些端点时,可以通过 adviceChain 属性为通知链提供 Bean 名称。此外,@Filter 注解还包含 discardWithinAdvice 属性,可用于配置丢弃行为,如通知过滤器章节所述。以下示例展示了在通知执行后执行丢弃操作:
📄️ 建议链中的排序建议
通知类属于“环绕”通知,并以嵌套方式应用。第一个通知是最外层的,而最后一个通知是最内层的(即最接近被通知的处理程序)。为了达到您期望的功能,正确排列通知类的顺序至关重要。
📄️ Advised Handler 属性
有时,在通知中访问处理程序的属性会很有用。例如,大多数处理程序都实现了 NamedComponent 接口,以便您访问组件名称。
📄️ 幂等接收器企业集成模式
从 4.1 版本开始,Spring Integration 提供了幂等接收器企业集成模式的实现。这是一种功能模式,整个幂等性逻辑应在应用程序中实现。然而,为了简化决策过程,框架提供了 IdempotentReceiverInterceptor 组件。这是一个应用于 MessageHandler.handleMessage() 方法的 AOP 通知,可根据其配置过滤请求消息或将其标记为重复消息。