Annotation Support
除了用于配置消息端点的 XML 命名空间支持之外,还可以使用标注。首先,Spring Integration 提供类级 @MessageEndpoint
作为模式化标注,这意味着它本身使用 Spring 的 @Component
标注进行了标注,因此由 Spring 的组件扫描自动识别为 Bean 定义。
更重要的是各种方法级标注。它们指示标注方法能够处理消息。以下示例演示了类级和方法级标注:
@MessageEndpoint
public class FooService {
@ServiceActivator
public void processMessage(Message message) {
...
}
}
对于方法以“handle
”Message 来说,其确切含义取决于特定标注。Spring Integration 中可用的标注包括:
-
@Aggregator
(see Aggregator) -
@Filter
(see Filter) -
@Router
(see Routers) -
@ServiceActivator
(see Service Activator) -
@Splitter
(see Splitter) -
@Transformer
(see Transformer) -
@InboundChannelAdapter
(see Channel Adapter) -
@BridgeFrom
(参见 Configuring a Bridge with Java Configuration) -
@BridgeTo
(参见 Configuring a Bridge with Java Configuration) -
@MessagingGateway
(see Messaging Gateways) -
@IntegrationComponentScan
(参见 Configuration and@EnableIntegration
)
如果您将 XML 配置与注解结合使用,则不需要 |
在大多数情况下,标注的处理程序方法不应该要求 Message
类型作为其参数。相反,方法参数类型可以匹配消息的有效负载类型,如下例所示:
public class ThingService {
@ServiceActivator
public void bar(Thing thing) {
...
}
}
当方法参数应该从 MessageHeaders
中的值进行映射时,另一种选择是使用参数级 @Header
标注。通常,使用 Spring Integration 标注标注的方法可以接受 Message
本身、消息有效负载或标头值(使用 @Header
)作为参数。事实上,方法可以接受组合,如下例所示:
public class ThingService {
@ServiceActivator
public void otherThing(String payload, @Header("x") int valueX, @Header("y") int valueY) {
...
}
}
您还可以使用 @Headers
标注将所有消息头作为 Map
提供,如下例所示:
public class ThingService {
@ServiceActivator
public void otherThing(String payload, @Headers Map<String, Object> headerMap) {
...
}
}
此注解的值也可以是 SpEL 表达式(例如, |
对于这些标注中的几个,当消息处理方法返回非空值时,端点会尝试发送答复。这与两个配置选项(命名空间和标注)保持一致,即这种端点的输出通道(如果可用)将被使用,而 REPLY_CHANNEL
消息头值则将用作后备方案。
端点上的输出通道和答复通道消息头的组合启用了一种管道方法,其中多个组件有一个输出通道,而最终组件允许答复报文被转发到答复通道(正如原始请求报文中指定的)。换句话说,最终组件取决于原始发送方提供的信息,结果可以动态地支持任意数量的客户端。这是一个 return address 模式的示例。 |
除了此处显示的示例之外,这些注释还支持 inputChannel
和 outputChannel
属性,如下例所示:
@Service
public class ThingService {
@ServiceActivator(inputChannel="input", outputChannel="output")
public void otherThing(String payload, @Headers Map<String, Object> headerMap) {
...
}
}
处理这些注释会创建与相应 XML 组件相同的 bean — AbstractEndpoint`实例和 `MessageHandler`实例(或入站通道适配器的 `MessageSource`实例)。请参阅 Annotations on `@Bean
Methods。bean 的名称根据以下模式生成:[componentName].[methodName].[decapitalizedAnnotationClassShortName]
。在上一个示例中,bean 的名称为 thingService.otherThing.serviceActivator
(对于 AbstractEndpoint
)和相同名称,以及额外的 .handler
(.source
)后缀(对于 MessageHandler
(MessageSource
) bean)。可以使用 @EndpointId`注释与这些消息传递注释一起来自定义此类名称。`MessageHandler`实例(`MessageSource`实例)也有资格被 the message history跟踪。
从版本 4.0 开始,所有消息传递注释都提供 `SmartLifecycle`选项(`autoStartup`和 `phase
),以允许在应用程序上下文初始化时对端点生命周期进行控制。它们分别默认为 true`和 `0
。要更改端点状态(例如 start()`或 `stop()
),您可以使用 BeanFactory
(或自动装配)获取对端点 bean 的引用并调用方法。或者,您可以向 Control Bus`发送命令消息(请参阅 Control Bus)。为此,您应该使用前一段中提到的 `beanName
。
在解析上述注释后自动创建的通道(当未配置特定通道 Bean 时)和相应的消费者端点会声明为 Bean,这些 Bean 在上下文初始化结束时会出现。这些 Bean 可以 在其他服务中自动装配,但它们必须标记为 @Lazy
注释,因为在常规自动装配过程中,这些定义通常仍不可用。
@Autowired
@Lazy
@Qualifier("someChannel")
MessageChannel someChannel;
...
@Bean
Thing1 dependsOnSPCA(@Qualifier("someInboundAdapter") @Lazy SourcePollingChannelAdapter someInboundAdapter) {
...
}
从 6.0 版本开始,所有消息注释现在都是 @Repeatable
,因此可以在相同服务方法上声明多次相同类型注释,这意味着要创建与重复注释的数量一样的端点:
@Transformer(inputChannel = "inputChannel1", outputChannel = "outputChannel1")
@Transformer(inputChannel = "inputChannel2", outputChannel = "outputChannel2")
public String transform(String input) {
return input.toUpperCase();
}
Using the @Poller
Annotation
在 Spring Integration 4.0 之前,消息注释要求 inputChannel
是对 SubscribableChannel
的引用。对于 PollableChannel
实例,需要使用 <int:bridge/>
元素来配置 <int:poller/>
,并使复合端点成为 PollingConsumer
。4.0 版本引入了 @Poller
注释,允许直接在消息注释上配置 poller
属性,如下例所示:
public class AnnotationService {
@Transformer(inputChannel = "input", outputChannel = "output",
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedDelay = "${poller.fixedDelay}"))
public String handle(String payload) {
...
}
}
@Poller
注释仅提供简单的 PollerMetadata
选项。可以使用属性占位符配置 @Poller
注释的属性(maxMessagesPerPoll
、fixedDelay
、fixedRate
和 cron
)。此外,从 5.1 版本开始,PollingConsumer
的 receiveTimeout
选项也已提供。如果需要提供更多轮询选项(例如 transaction
、advice-chain
、error-handler
等),应将 PollerMetadata
配置为通用 Bean,并使用其 Bean 名称作为 @Poller
的 value
属性。在这种情况下,不允许使用其他属性(它们必须在 PollerMetadata
Bean 上指定)。请注意,如果 inputChannel
是 PollableChannel
,并且未配置 @Poller
,则会使用默认 PollerMetadata
(如果它存在于应用程序上下文中)。若要使用 @Configuration
注释声明默认轮询器,请使用与以下示例类似的代码:
@Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(10));
return pollerMetadata;
}
以下示例显示如何使用默认轮询器:
public class AnnotationService {
@Transformer(inputChannel = "aPollableChannel", outputChannel = "output")
public String handle(String payload) {
...
}
}
以下示例显示如何使用具名轮询器:
@Bean
public PollerMetadata myPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(1000));
return pollerMetadata;
}
以下示例展示了使用默认轮询器的端点:
public class AnnotationService {
@Transformer(inputChannel = "aPollableChannel", outputChannel = "output"
poller = @Poller("myPoller"))
public String handle(String payload) {
...
}
}
从版本 4.3.3 开始,@Poller`注释具有 `errorChannel`属性,以便更容易配置基础 `MessagePublishingErrorHandler
。此属性在 `<poller>`XML 组件中扮演与 `error-channel`相同的作用。有关更多信息,请参阅 Endpoint Namespace Support。
消息注释上的 poller()
属性与 reactive()
属性互斥。有关详细信息,请参见下一节。
Using @Reactive
Annotation
ReactiveStreamsConsumer
自 5.0 版本以来一直存在,但仅在端点的输入通道是 FluxMessageChannel
(或任何 org.reactivestreams.Publisher
实现)时才应用。从 5.3 版本开始,即使输入通道类型,框架也会在其实例创建目标消息处理程序为 ReactiveMessageHandler
时创建其实例。对于从 5.5 版本开始的所有消息注释,都引入了 @Reactive
子注释(与上面提到的 @Poller
类似)。它接受可选的 Function<? super Flux<Message<?>>, ? extends Publisher<Message<?>>>
Bean 引用,并且独立于输入通道类型和消息处理程序,将目标端点转换为 ReactiveStreamsConsumer
实例。此函数是从 Flux.transform()
运算符使用的,以在来自输入通道的响应流源上应用一些自定义(publishOn()
、doOnNext()
、log()
、retry()
等)。
以下示例演示如何独立于最终订阅者和 DirectChannel
的生成器,从输入通道更改发布线程:
@Bean
public Function<Flux<?>, Flux<?>> publishOnCustomizer() {
return flux -> flux.publishOn(Schedulers.parallel());
}
@ServiceActivator(inputChannel = "directChannel", reactive = @Reactive("publishOnCustomizer"))
public void handleReactive(String payload) {
...
}
消息传递注释上的 reactive()`属性与 `poller()`属性互斥。有关更多信息,请参阅 Using the `@Poller
Annotation和 Reactive Streams Support。
Using the @InboundChannelAdapter
Annotation
4.0 版中引入了 @InboundChannelAdapter
方法级注解。它根据标注方法的 MethodInvokingMessageSource
来生成一个 SourcePollingChannelAdapter
集成组件。此注解类似于 <int:inbound-channel-adapter>
XML 组件,并具有相同的限制:该方法不能有参数,且返回类型不能为 void
。它有两个属性:value
(必需的 MessageChannel
Bean 名)和 poller
(可选的 @Poller
注解,如 described earlier)。如果您需要提供一些 MessageHeaders
,可以使用 Message<?>
返回类型,并使用 MessageBuilder
来构建 Message<?>
。使用 MessageBuilder
让您可以配置 MessageHeaders
。以下示例演示了如何使用 @InboundChannelAdapter
注解:
@InboundChannelAdapter("counterChannel")
public Integer count() {
return this.counter.incrementAndGet();
}
@InboundChannelAdapter(value = "fooChannel", poller = @Poller(fixed-rate = "5000"))
public String foo() {
return "foo";
}
4.3 版本引入了 channel
别名,用于 value
注释属性,以提供更好的源代码可读性。此外,目标 MessageChannel
Bean 是在第一次 receive()
调用期间而不是在初始化阶段由指定的名称(由 outputChannelName
选项设置)在 SourcePollingChannelAdapter
中解析的。它允许使用“延迟绑定”逻辑:从消费者的角度来看,目标 MessageChannel
Bean 会在稍晚于 @InboundChannelAdapter
解析阶段创建并注册。
第一个示例要求已在应用程序上下文中声明了默认轮询器。
使用 @MessagingGateway
注释
Using the @IntegrationComponentScan
Annotation
标准 Spring 框架 @ComponentScan
注解不会扫描接口的模式 @Component
注解。为了克服此限制并允许 @MessagingGateway
配置(参见 @MessagingGateway
Annotation),我们引入了 @IntegrationComponentScan
机制。此注解必须与 @Configuration
注解一起放置,并定制以定义其扫描选项,例如 basePackages
和 basePackageClasses
。在这种情况下,所有带有 @MessagingGateway
标注的发现的接口都将被解析并注册为 GatewayProxyFactoryBean
实例。所有其他基于类的组件都将由标准 @ComponentScan
解析。