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