Spring ApplicationEvent Support

Spring Integration 提供对入站和出站 ApplicationEvents 的支持,如底层的 Spring Framework 所定义。有关 Spring 对事件和侦听器的支持的详细信息,请参见 Spring Reference Manual

Spring Integration provides support for inbound and outbound ApplicationEvents, as defined by the underlying Spring Framework. For more information about Spring’s support for events and listeners, see the Spring Reference Manual.

你需要将此依赖项包含在你的项目中:

You need to include this dependency into your project:

  • 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 本身会作为有效载荷传递。

To receive events and send them to a channel, you can define an instance of Spring Integration’s ApplicationEventListeningMessageProducer. This class is an implementation of Spring’s ApplicationListener interface. By default, it passes all received events as Spring Integration messages. To limit based on the type of event, you can use the 'eventTypes' property to configure the list of event types that you want to receive. If a received event has a Message instance as its 'source', that Message is passed as-is. Otherwise, if a SpEL-based payloadExpression has been provided, that is evaluated against the ApplicationEvent instance. If the event’s source is not a Message instance and no payloadExpression has been provided, the ApplicationEvent itself is passed as the payload.

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

Starting with version 4.2, the ApplicationEventListeningMessageProducer implements GenericApplicationListener and can be configured to accept not only ApplicationEvent types but any type for treating payload events (which are also supported since Spring Framework 4.2). When the accepted event is an instance of PayloadApplicationEvent, its payload is used for the message to send.

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

For convenience, namespace support is provided to configure an ApplicationEventListeningMessageProducer with the inbound-channel-adapter element, as the following example shows:

<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 且下游通道是同步的,则该异常会传播到调用者。

In the preceding example, all application context events that match one of the types specified by the 'event-types' (optional) attribute are delivered as Spring Integration messages to the message channel named 'eventChannel'. If a downstream component throws an exception, a MessagingException that contains the failed message and exception is sent to the channel named 'eventErrorChannel'. If no error-channel is specified and the downstream channels are synchronous, the exception is propagated to the caller.

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

Using Java to configure the same adapter:

@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:

With the 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 之间的桥梁。

To send Spring ApplicationEvents, create an instance of the ApplicationEventPublishingMessageHandler and register it within an endpoint. This implementation of the MessageHandler interface also implements Spring’s ApplicationEventPublisherAware interface and consequently acts as a bridge between Spring Integration messages and ApplicationEvents.

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

For convenience, namespace support is provided to configure an ApplicationEventPublishingMessageHandler with the outbound-channel-adapter element, as the following example shows:

<int:channel id="eventChannel"/>

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

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

If you use a PollableChannel (such as a QueueChannel), you can also provide a poller child element of the outbound-channel-adapter element. You can also optionally provide a task-executor reference for that poller. The following example demonstrates both:

<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 实例中。

In the preceding example, all messages sent to the 'eventChannel' channel are published as ApplicationEvent instances to any relevant ApplicationListener instances that are registered within the same Spring ApplicationContext. If the payload of the message is an ApplicationEvent, it is passed as-is. Otherwise, the message itself is wrapped in a MessagingEvent instance.

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

Starting with version 4.2, you can configure the ApplicationEventPublishingMessageHandler (<int-event:outbound-channel-adapter>) with the publish-payload boolean attribute to publish to the application context payload as is, instead of wrapping it to a MessagingEvent instance.

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

To configure the adapter using Java configuration:

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

使用 Java DSL:

With the 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 结合使用:

The @Publisher annotation also can be used in combination with an @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 的详细信息,请参见更多信息。

In this case a return value of the event listener method is used as a payload for a Message to be published to that eventFromPublisher channel. See more information about the @Publisher in the Annotation-driven Configuration section.