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