[[applicationevent]]
= Spring `ApplicationEvent` Support

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 https://docs.spring.io/spring-framework/reference/core/beans/context-introduction.html#context-functionality-events[Spring Reference Manual].

You need to include this dependency into your project:

[tabs]
======
Maven::
+
[source, xml, subs="normal", role="primary"]
----
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-event</artifactId>
    <version>{project-version}</version>
</dependency>
----

Gradle::
+
[source, groovy, subs="normal", role="secondary"]
----
compile "org.springframework.integration:spring-integration-event:{project-version}"
----
======

[[appevent-inbound]]
== Receiving Spring Application Events

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.

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.

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

[source,xml]
----
<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"/>
----

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.

Using Java to configure the same adapter:

[source, 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;
}
----

With the Java DSL:

[source, java]
----
@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();
}
----

[[appevent-outbound]]
== Sending Spring Application Events

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`.

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

[source,xml]
----
<int:channel id="eventChannel"/>

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

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:

[source,xml]
----
<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"/>
----

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.

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.

To configure the adapter using Java configuration:

[source, java]
----
@Bean
@ServiceActivator(inputChannel = "eventChannel")
public ApplicationEventPublishingMessageHandler eventHandler() {
    ApplicationEventPublishingMessageHandler handler =
            new ApplicationEventPublishingMessageHandler();
    handler.setPublishPayload(true);
    return handler;
}
----

With the Java DSL:

[source, java]
----
@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);
}
----

The `@Publisher` annotation also can be used in combination with an `@EventListener`:

[source, java]
----
@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();
     }

}
----

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 xref:message-publishing.adoc#publisher-annotation[Annotation-driven Configuration] section.
