Spring ApplicationEvent Support

Spring Integration 提供对入站和出站 ApplicationEvents 的支持,如底层的 Spring Framework 所定义。有关 Spring 对事件和侦听器的支持的详细信息,请参见 Spring Reference Manual。 你需要将此依赖项包含在你的项目中:

  • Maven

  • Gradle

<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-event</artifactId>
    <version>{project-version}</version>
</dependency>
compile "org.springframework.integration:spring-integration-event:{project-version}"

Receiving Spring Application Events

若要接收事件并将其发送到通道,你可以定义 Spring 集成的 ApplicationEventListeningMessageProducer 实例。此类是 Spring 的 ApplicationListener 接口的实现。默认情况下,它将所有接收到的事件作为 Spring 集成消息传递。若要基于事件类型进行限制,你可以使用 'eventTypes' 属性来配置想要接收的事件类型列表。如果收到的事件将其 Message 实例作为其“来源”,那么该 Message 会按原样传递。否则,如果已提供基于 SpEL 的 payloadExpression,那么会根据 ApplicationEvent 实例评估该 SpEL。如果该事件的来源不是 Message 实例,并且没有提供 payloadExpression,那么 ApplicationEvent 本身会作为有效载荷传递。

从版本 4.2 开始,ApplicationEventListeningMessageProducer 实现 GenericApplicationListener,并且配置为不仅接受 ApplicationEvent 类型,还接受任何用于处理有效载荷事件(Spring Framework 4.2 以来也受支持)的类型。当已接受的事件是 PayloadApplicationEvent 实例时,它的 payload 用于要发送的消息。

为方便起见,提供了命名空间支持,可以使用 inbound-channel-adapter 元素配置 ApplicationEventListeningMessageProducer,如下例所示:

<int-event:inbound-channel-adapter channel="eventChannel"
                                   error-channel="eventErrorChannel"
                                   event-types="example.FooEvent, example.BarEvent, java.util.Date"/>

<int:publish-subscribe-channel id="eventChannel"/>

在前面的示例中,所有与“event-types”(可选)属性指定的其中一种类型匹配的应用程序上下文事件作为 Spring 集成消息传递到名为“eventChannel”的消息通道。如果下游组件抛出异常,则会将包含失败消息和异常的 MessagingException 发送到名为“eventErrorChannel”的通道。如果未指定 error-channel 且下游通道是同步的,则该异常会传播到调用者。

使用 Java 配置相同的适配器:

@Bean
public ApplicationEventListeningMessageProducer eventsAdapter(
            MessageChannel eventChannel, MessageChannel eventErrorChannel) {

    ApplicationEventListeningMessageProducer producer =
        new ApplicationEventListeningMessageProducer();
    producer.setEventTypes(example.FooEvent.class, example.BarEvent.class, java.util.Date.class);
    producer.setOutputChannel(eventChannel);
    producer.setErrorChannel(eventErrorChannel);
    return producer;
}

使用 Java DSL:

@Bean
public ApplicationEventListeningMessageProducer eventsAdapter() {

    ApplicationEventListeningMessageProducer producer =
        new ApplicationEventListeningMessageProducer();
    producer.setEventTypes(example.FooEvent.class, example.BarEvent.class, java.util.Date.class);
    return producer;
}

@Bean
public IntegrationFlow eventFlow(ApplicationEventListeningMessageProducer eventsAdapter,
        MessageChannel eventErrorChannel) {

    return IntegrationFlow.from(eventsAdapter, e -> e.errorChannel(eventErrorChannel))
        .handle(...)
        ...
        .get();
}

Sending Spring Application Events

若要发送 Spring ApplicationEvents,请创建 ApplicationEventPublishingMessageHandler 实例并在端点内注册该实例。此 MessageHandler 接口的实现还实现了 Spring 的 ApplicationEventPublisherAware 接口,因此充当 Spring 集成消息和 ApplicationEvents 之间的桥梁。

为方便起见,提供了命名空间支持,可以使用 outbound-channel-adapter 元素配置 ApplicationEventPublishingMessageHandler,如下例所示:

<int:channel id="eventChannel"/>

<int-event:outbound-channel-adapter channel="eventChannel"/>

如果使用 PollableChannel(比如 QueueChannel),也可以提供 outbound-channel-adapter 元素的 poller 子元素。还可以为那个 poller 可选地提供 task-executor 引用。以下示例展示了这两个操作:

<int:channel id="eventChannel">
  <int:queue/>
</int:channel>

<int-event:outbound-channel-adapter channel="eventChannel">
  <int:poller max-messages-per-poll="1" task-executor="executor" fixed-rate="100"/>
</int-event:outbound-channel-adapter>

<task:executor id="executor" pool-size="5"/>

在上一个示例中,发送到 eventChannel 通道的全部消息都作为 ApplicationEvent 实例发布给任何在同一个 Spring ApplicationContext 内注册的相关 ApplicationListener 实例。如果消息的 payload 是 ApplicationEvent,则原样传递。否则,消息本身会包装在 MessagingEvent 实例中。

从 4.2 版本开始,可以使用 publish-payload 布尔属性针对 ApplicationEventPublishingMessageHandler<int-event:outbound-channel-adapter>)进行配置,以按原样发布到应用程序上下文 payload,而不将其包装到 MessagingEvent 实例中。

使用 Java 配置针对适配器进行配置:

@Bean
@ServiceActivator(inputChannel = "eventChannel")
public ApplicationEventPublishingMessageHandler eventHandler() {
    ApplicationEventPublishingMessageHandler handler =
            new ApplicationEventPublishingMessageHandler();
    handler.setPublishPayload(true);
    return handler;
}

使用 Java DSL:

@Bean
public ApplicationEventPublishingMessageHandler eventHandler() {
    ApplicationEventPublishingMessageHandler handler =
            new ApplicationEventPublishingMessageHandler();
    handler.setPublishPayload(true);
    return handler;
}

@Bean
// MessageChannel is "eventsFlow.input"
public IntegrationFlow eventsOutFlow(ApplicationEventPublishingMessageHandler eventHandler) {
    return f -> f.handle(eventHandler);
}

@Publisher 注解也可以与 @EventListener 结合使用:

@Configuration
@EnableIntegration
@EnablePublisher
public static class ContextConfiguration {

     @Bean
     QueueChannel eventFromPublisher() {
         return new QueueChannel();
     }

     @EventListener
     @Publisher("eventFromPublisher")
     public String publishEventToChannel(TestApplicationEvent3 testApplicationEvent3) {
         return testApplicationEvent3.getSource().toString();
     }

}

在这种情况下,将事件侦听器方法的返回值用作发布到该 eventFromPublisher 通道的 Message 的有效负载。有关 Annotation-driven Configuration 部分中 @Publisher 的详细信息,请参见更多信息。