对于最新的稳定版本,请使用 Spring Integration 6.3.1! |
对于最新的稳定版本,请使用 Spring Integration 6.3.1! |
服务激活器是用于将任何 Spring 托管对象连接到输入通道的端点类型,以便它可以扮演服务的角色。
如果服务产生输出,它也可以连接到输出通道。
或者,输出生成服务可以位于处理管道或消息流的末尾,在这种情况下,可以使用入站消息的标头。
如果未定义输出通道,则这是默认行为。
与此处描述的大多数配置选项一样,相同的行为实际上适用于大多数其他组件。replyChannel
服务激活器本质上是一个通用终结点,用于使用输入消息(有效负载和标头)对某个对象调用方法。
它的内部逻辑基于一个,它可以是特定用例的任何可能的实现,例如、、等。
因此,本参考手册中提到的任何出站网关和出站通道适配器都应被视为此服务激活器端点的特定扩展;最后,它们都会调用某个对象的方法。MessageHandler
DefaultMessageSplitter
AggregatingMessageHandler
SftpMessageHandler
JpaOutboundGateway
配置服务激活器
使用 Java & Annotation 配置,只需用 annotation 标记相应的服务方法就足够了 - 当从输入通道使用消息时,框架会调用它:@ServiceActivator
public class SomeService {
@ServiceActivator(inputChannel = "exampleChannel")
public void exampleHandler(SomeData payload) {
...
}
}
有关详细信息,请参阅注释支持。
对于 Java、Groovy 或 Kotlin DSL,an 的运算符表示服务激活器:.handle()
IntegrationFlow
-
Java DSL
-
Kotlin DSL
-
Groovy DSL
@Bean
public IntegrationFlow someFlow() {
return IntegrationFlow
.from("exampleChannel")
.handle(someService, "exampleHandler")
.get();
}
@Bean
fun someFlow() =
integrationFlow("exampleChannel") {
handle(someService, "exampleHandler")
}
@Bean
someFlow() {
integrationFlow 'exampleChannel',
{
handle someService, 'exampleHandler'
}
}
有关 DSL 的更多信息,请参阅相应章节:
若要在使用 XML 配置时创建服务激活器,请使用带有“input-channel”和“ref”属性的“service-activator”元素,如以下示例所示:
<int:service-activator input-channel="exampleChannel" ref="exampleHandler"/>
上述配置从中选择满足其中一个消息传递要求的所有方法,如下所示:exampleHandler
-
注释为
@ServiceActivator
-
是
public
-
如果出现以下情况,则不返回
void
requiresReply == true
在运行时调用的目标方法按每个请求消息的类型选择,或者如果目标类上存在此类方法,则将其作为对类型的回退。payload
Message<?>
从版本 5.0 开始,可以将一种服务方法标记为所有不匹配情况的回退。
当使用内容类型转换时,这在转换后调用目标方法时非常有用。@org.springframework.integration.annotation.Default
若要委托给任何对象的显式定义方法,可以添加该属性,如以下示例所示:method
<int:service-activator input-channel="exampleChannel" ref="somePojo" method="someMethod"/>
无论哪种情况,当服务方法返回非 null 值时,终结点都会尝试将回复消息发送到相应的回复通道。
要确定应答通道,它首先检查终端节点配置中是否提供了应答通道,如以下示例所示:output-channel
<int:service-activator input-channel="exampleChannel" output-channel="replyChannel"
ref="somePojo" method="someMethod"/>
如果该方法返回结果并且定义了 no,则框架将检查请求消息的标头值。
如果该值可用,则检查其类型。
如果是 ,则应答消息将发送到该通道。
如果是 ,则终结点会尝试将通道名称解析为通道实例。
如果无法解析通道,则抛出 a。
如果可以解决,则将消息发送到那里。
如果请求消息没有标头,并且对象是 ,则会为目标目标查询其标头。
这是 Spring Integration 中用于请求-回复消息传递的技术,也是返回地址模式的一个示例。output-channel
replyChannel
MessageChannel
String
DestinationResolutionException
replyChannel
reply
Message
replyChannel
如果方法返回结果,并且要放弃该结果并结束流,则应将 发送到 .
为方便起见,框架注册了一个名为 .
有关详细信息,请参阅特殊频道。output-channel
NullChannel
nullChannel
服务激活器是生成回复消息不需要的组件之一。
如果方法返回或具有返回类型,则服务激活器将在方法调用后退出,而没有任何信号。
此行为可由该选项控制,该选项在使用 XML 命名空间进行配置时也会公开。
如果该标志设置为 并且该方法返回 null,则会引发 a。null
void
AbstractReplyProducingMessageHandler.requiresReply
requires-reply
true
ReplyRequiredException
service 方法中的参数可以是消息,也可以是任意类型。
如果是后者,则假定它是消息有效负载,该负载从消息中提取并注入到服务方法中。
我们通常推荐这种方法,因为它在使用 Spring Integration 时遵循并推广了 POJO 模型。
参数也可以有 或 注释,如注释支持中所述。@Header
@Headers
服务方法不需要有任何参数,这意味着您可以实现事件样式的服务激活器(您只关心服务方法的调用),而不必担心消息的内容。 将其视为空 JMS 消息。 此类实现的一个示例用例是存储在输入通道上的消息的简单计数器或监视器。 |
从 V4.1 开始,框架正确地将消息属性 ( 和 ) 转换为 Java 8 POJO 方法参数,如以下示例所示:payload
headers
Optional
public class MyBean {
public String computeValue(Optional<String> payload,
@Header(value="foo", required=false) String foo1,
@Header(value="foo") Optional<String> foo2) {
if (payload.isPresent()) {
String value = payload.get();
...
}
else {
...
}
}
}
如果自定义服务激活程序处理程序实现可以在其他定义中重用,我们通常建议使用属性。
但是,如果自定义服务激活程序处理程序实现仅在 的单个定义中使用,则可以提供内 Bean 定义,如以下示例所示:ref
<service-activator>
<service-activator>
<int:service-activator id="exampleServiceActivator" input-channel="inChannel"
output-channel = "outChannel" method="someMethod">
<beans:bean class="org.something.ExampleServiceActivator"/>
</int:service-activator>
不允许在同一配置中同时使用属性和内部处理程序定义,因为它会创建不明确的条件并导致引发异常。ref <service-activator> |
如果属性引用了扩展的 Bean(例如框架本身提供的处理程序),则通过将输出通道直接注入处理程序来优化配置。
在这种情况下,每个实例都必须指向单独的 Bean 实例(或 -scoped bean)或使用内部配置类型。
如果无意中引用了多个 Bean 中的同一消息处理程序,则会出现配置异常。ref AbstractMessageProducingHandler ref prototype <bean/> |
服务激活器和 Spring 表达式语言 (SpEL)
从 Spring Integration 2.0 开始,服务激活器也可以从 SpEL 中受益。
例如,您可以调用任何 Bean 方法,而无需指向属性中的 Bean 或将其作为内部 Bean 定义包含在内 Bean 中,如下所示:ref
<int:service-activator input-channel="in" output-channel="out"
expression="@accountService.processAccount(payload, headers.accountId)"/>
<bean id="accountService" class="thing1.thing2.Account"/>
在前面的配置中,我们没有使用 or 作为内 Bean 来注入 'accountService',而是使用 SpEL 的表示法并调用一个方法,该方法采用与消息有效负载兼容的类型。
我们还传递一个标头值。
可以根据消息中的任何内容评估任何有效的 SpEL 表达式。
对于简单的方案,如果所有逻辑都可以封装在这样的表达式中,则服务激活器不需要引用 bean,如以下示例所示:ref
@beanId
<int:service-activator input-channel="in" output-channel="out" expression="payload * 2"/>
在前面的配置中,我们的服务逻辑是将有效负载值乘以 2。 SpEL 让我们相对容易地处理它。
有关配置服务激活器的更多信息,请参阅 Java DSL 一章中的服务激活器和 .handle()
方法。
服务方法不需要有任何参数,这意味着您可以实现事件样式的服务激活器(您只关心服务方法的调用),而不必担心消息的内容。 将其视为空 JMS 消息。 此类实现的一个示例用例是存储在输入通道上的消息的简单计数器或监视器。 |
不允许在同一配置中同时使用属性和内部处理程序定义,因为它会创建不明确的条件并导致引发异常。ref <service-activator> |
如果属性引用了扩展的 Bean(例如框架本身提供的处理程序),则通过将输出通道直接注入处理程序来优化配置。
在这种情况下,每个实例都必须指向单独的 Bean 实例(或 -scoped bean)或使用内部配置类型。
如果无意中引用了多个 Bean 中的同一消息处理程序,则会出现配置异常。ref AbstractMessageProducingHandler ref prototype <bean/> |
异步服务激活器
服务激活器由调用线程调用。
如果输入通道是 的 或 的轮询器线程,则这是一个上游线程。
如果服务返回 ,则默认操作是将其作为发送到输出(或应答)通道的消息的有效负载发送。
从 V4.3 开始,您现在可以将属性设置为(在使用 Java 配置时使用)。
如果服务返回 when this 属性设置为 ,则会立即释放调用线程,并在完成未来的线程上(从服务内部)发送应答消息。
这对于使用 的长时间运行的服务特别有利,因为释放轮询器线程是为了在框架内执行其他服务。SubscribableChannel
PollableChannel
CompletableFuture<?>
async
true
setAsync(true)
CompletableFuture<?>
async
true
PollableChannel
如果服务以 完成 ,则会进行正常的错误处理。
如果存在,则将 An 发送到邮件头。
否则,将 an 发送到默认值(如果可用)。Exception
ErrorMessage
errorChannel
ErrorMessage
errorChannel
从版本 6.1 开始,如果将 的输出通道配置为 ,则默认情况下将打开异步模式。
如果处理程序结果不是反应式 或 ,则无论输出通道类型如何,都会发生常规的回复生成过程。AbstractMessageProducingHandler
ReactiveStreamsSubscribableChannel
CompletableFuture<?>
有关更多信息,另请参阅反应式流支持。
服务激活器和方法返回类型
服务方法可以返回任何成为回复消息有效负载的类型。
在这种情况下,将创建一个新对象,并复制请求消息中的所有标头。
对于大多数 Spring Integration 实现,当交互基于 POJO 方法调用时,这同样有效。Message<?>
MessageHandler
也可以从该方法返回一个完整的对象。
但是,请记住,与转换器不同,对于服务激活器,如果返回的消息中尚不存在标头,则将通过从请求消息中复制标头来修改此消息。
因此,如果 method 参数为 a,并且复制了服务方法中的一些(但不是全部)现有标头,则它们将重新出现在回复消息中。
从回复消息中删除标头不是 Service Activator 的责任,遵循松散耦合原则,最好在集成流中添加 a。
或者,可以使用 Transformer 代替 Service Activator,但在这种情况下,当返回完整消息时,该方法完全负责消息,包括复制请求消息标头(如果需要)。
您必须确保必须保留重要的框架标头(例如 , ),如果存在。Message<?>
Message<?>
HeaderFilter
Message<?>
replyChannel
errorChannel