为端点添加行为
在 Spring Integration 2.2 之前,您可以通过向轮询器的 <advice-chain/>
元素添加 AOP 建议来为整个集成流添加行为。但是,假设您只想重试,比如说,仅重试 REST Web 服务调用,而不重试任何下游端点。
例如,考虑以下流程:
inbound-adapter->poller->http-gateway1->http-gateway2->jdbc-outbound-adapter
如果你在轮询器的建议链中配置了一些重试逻辑,且调用 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\<?>, Mono\<?>, Publisher\<?>>,它会在拦截的 handleRequestMessage() 方法实现所生成的回复上调用 Mono.transform() 操作符时被调用。通常,当我们要通过 timeout()、retry() 等支持操作符来控制网络波动时,这种 Mono 定制是必要的。例如,当我们通过 WebFlux 客户端发起 HTTP 请求时,我们可以使用以下配置,以确保等待响应的时间不超过 5 秒:
📄️ 上下文持有者建议
从 6.1 版本开始,引入了 ContextHolderRequestHandlerAdvice。这个建议从请求消息中获取某些值并将其存储在上下文持有者中。当目标 MessageHandler 上的执行完成时,该值会从上下文中清除。理解这个建议的最佳方式是类似于编程流程,我们将某个值存储到 ThreadLocal 中,在目标调用中访问它,然后在执行后清理 ThreadLocal。ContextHolderRequestHandlerAdvice 需要这些构造函数参数:一个 Function\<Message\<?>, Object> 作为值提供者,Consumer\<Object> 作为上下文设置回调,以及 Runnable 作为上下文清理钩子。
📄️ 自定义建议类
除了前面描述的提供的建议类之外,你还可以实现自己的建议类。虽然你可以提供 org.aopalliance.aop.Advice (通常是 org.aopalliance.intercept.MethodInterceptor ) 的任何实现,但我们通常建议你继承 o.s.i.handler.advice.AbstractRequestHandlerAdvice。这有助于避免编写低级别的面向方面编程代码,并提供一个为此环境量身定制的起点。
📄️ 其他建议链元素
虽然上述抽象类是一个便利,但你可以将任何建议(包括事务建议)添加到链中。
📄️ 处理消息建议
如本节引言所述,请求处理程序建议链中的建议对象仅应用于当前端点,而不应用于下游流程(如果有的话)。对于生成回复的 MessageHandler 对象(例如那些扩展了 AbstractReplyProducingMessageHandler 的对象),建议应用于内部方法:handleRequestMessage()(由 MessageHandler.handleMessage() 调用)。对于其他消息处理程序,建议应用于 MessageHandler.handleMessage()。
📄️ 事务支持
从 5.0 版本开始,引入了一个新的 TransactionHandleMessageAdvice,以使整个下游流程事务化,这要归功于 HandleMessageAdvice 的实现。当在 \<request-handler-advice-chain> 元素中使用常规的 TransactionInterceptor(例如,通过配置 \<tx:advice>),启动的事务仅适用于内部 AbstractReplyProducingMessageHandler.handleRequestMessage(),并不会传播到下游流程。
📄️ 建议的过滤器
在建议 Filter 建议时,有一个额外的考虑因素。默认情况下,任何丢弃操作(当过滤器返回 false 时)都在建议链的作用范围内执行。这可能包括丢弃通道下游的所有流程。因此,例如,如果丢弃通道下游的一个元素抛出异常并且存在重试建议,则该过程将被重试。此外,如果 throwExceptionOnRejection 设置为 true(异常是在建议的作用范围内抛出的)。
📄️ 使用注解建议端点
当使用注解(@Filter、@ServiceActivator、@Splitter 和 @Transformer)配置某些端点时,您可以在 adviceChain 属性中为建议链提供一个 bean 名称。此外,@Filter 注解还具有 discardWithinAdvice 属性,可用于配置丢弃行为,如在《建议过滤器》中所述。以下示例会导致在建议之后执行丢弃:
📄️ 在建议链中排序建议
建议类是围绕着“around”建议,并以嵌套的方式应用。第一个建议是最外层的,而最后一个建议是最内层的(即,最接近被建议的处理程序)。将建议类按正确顺序放置非常重要,以实现您期望的功能。
📄️ 建议的处理器属性
有时,从建议内部访问处理程序属性很有用。例如,大多数处理程序实现了 NamedComponent 以让你访问组件名称。
📄️ 幂等接收器 企业集成模式
从 4.1 版本开始,Spring Integration 提供了对幂等接收器企业集成模式的实现。它是一个函数式模式,所有的幂等逻辑都应该在应用程序中实现。然而,为了简化决策,提供了 IdempotentReceiverInterceptor 组件。这是一个 AOP 建议,应用于 MessageHandler.handleMessage() 方法,可以根据其配置过滤请求消息或将其标记为重复。