# Spring 应用事件支持

##  Spring `ApplicationEvent`支持

Spring 集成提供了对入站和出站`ApplicationEvents`的支持，如底层 Spring 框架所定义的那样。有关 Spring 对事件和侦听器的支持的更多信息，请参见[Spring Reference Manual](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#context-functionality-events)。

你需要在项目中包含此依赖项：

Maven

```
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-event</artifactId>
    <version>5.5.9</version>
</dependency>
```

Gradle

```
compile "org.springframework.integration:spring-integration-event:5.5.9"
```

### 接收 Spring 应用事件

要接收事件并将其发送到通道，你可以定义 Spring Integration 的`ApplicationEventListeningMessageProducer`实例。这个类是 Spring 的`ApplicationListener`接口的实现。默认情况下，它将所有接收到的事件作为 Spring 集成消息传递。要根据事件的类型进行限制，可以使用“eventTypes”属性来配置要接收的事件类型列表。如果接收到的事件有一个`Message`实例作为其“源”，则该`Message`将按原样传递。否则，如果提供了基于 SPEL 的`payloadExpression`，则根据`ApplicationEvent`实例对其进行求值。如果事件的源不是`Message`实例，并且没有提供`payloadExpression`，则`ApplicationEvent`本身将作为有效负载传递。

从版本 4.2 开始，`ApplicationEventListeningMessageProducer`实现了`GenericApplicationListener`，并且可以被配置为不仅接受`ApplicationEvent`类型，还接受用于处理有效负载事件的任何类型（自 Spring Framework4.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”的通道。如果指定了 no`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 IntegrationFlows.from(eventsAdapter, e -> e.errorChannel(eventErrorChannel))
        .handle(...)
        ...
        .get();
}
```

### 发送 Spring 应用程序事件

要发送 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`），还可以提供`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 `ApplicationListener`中注册的任何相关`ApplicationContext`实例。如果消息的有效负载是`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);
}
```