[note] this article is translated from: Spring Events | Baeldung
In this tutorial, we will discuss how to use events in Spring.
Event is one of the most overlooked functions in the framework, but it is also one of the more useful functions. Like many other things in Spring, event publishing is one of the features provided by ApplicationContext.
There are some simple guidelines to follow:
- If we use the spring framework before 4.2, the event class should extend ApplicationEvent. Starting with version 4.2 , the event class no longer needs to extend the ApplicationEvent class.
- The publisher should inject an ApplicationEventPublisher object.
The listener should implement the ApplicationListener interface.
2. User defined eventsSpring allows us to create and publish custom events that are synchronized by default. This has some advantages, such as the listener's ability to participate in the publisher's transaction context.
2.1. A simple application event
Let's create a simple event class -- just a placeholder for storing event data.
In this case, the event class contains a String message:
public class CustomSpringEvent extends ApplicationEvent { private String message; public CustomSpringEvent(Object source, String message) { super(source); this.message = message; } public String getMessage() { return message; } }
2.2. Publisher
Now let's create the publisher of the event. The publisher constructs the event object and publishes it to anyone who is listening.
To publish events, publishers can simply inject ApplicationEventPublisher and use the publishEvent() API:
@Component public class CustomSpringEventPublisher { @Autowired private ApplicationEventPublisher applicationEventPublisher; public void publishCustomEvent(final String message) { System.out.println("Publishing custom event. "); CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message); applicationEventPublisher.publishEvent(customSpringEvent); } }
Alternatively, the publisher class can implement
ApplicationEventPublisherAware interface, which also injects the event publisher when the application starts. In general, injecting @ Autowire into publishers is easier.
Starting with Spring Framework 4.2, the ApplicationEventPublisher interface provides a new overload for the publishEvent(Object event) method, which accepts any object as an event. Therefore, Spring events no longer need to extend the ApplicationEvent class.
2.3. Listener
Finally, let's create a listener.
The only requirement for a listener is a bean and implements the ApplicationListener interface:
@Component public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> { @Override public void onApplicationEvent(CustomSpringEvent event) { System.out.println("Received spring custom event - " + event.getMessage()); } }
Notice how our custom listener parameterizes with the generic types of custom events, which makes the onApplicationEvent() method type safe. This also avoids having to check whether the object is an instance of a specific event class and convert it.
Moreover, as already discussed (Spring events are synchronized by default), the dostufandpublishanevent () method blocks until all listeners finish processing the event.
3. Create asynchronous eventsIn some cases, publishing events synchronously is not what we really want -- we may need to process our events asynchronously.
We can do this by creating a
The applicationeventmulticast bean opens it in configuration.
For us, the SimpleAsyncTaskExecutor does this very well:
@Configuration public class AsynchronousSpringEventsConfig { @Bean(name = "applicationEventMulticaster") public ApplicationEventMulticaster simpleApplicationEventMulticaster() { SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster(); eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor()); return eventMulticaster; } }
The event, publisher, and listener implementations are the same as before, but now the listener will process events asynchronously in a separate thread.
4. Existing framework eventsSpring itself publishes various out of the box events. For example, ApplicationContext will trigger various framework events: ContextRefreshedEvent, ContextStartedEvent, RequestHandledEvent, etc.
These events provide application developers with an option to connect to the application lifecycle and context and add their own custom logic where needed.
This is a quick example of a listener listening for context refresh:
public class ContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent cse) { System.out.println("Handling context re-freshed event. "); } }
To learn more about existing framework events, check here Our next tutorial.
5. Annotation driven event listenerStarting from Spring 4.2, the event listener does not need to be a bean that implements the applicationlister interface -- it can be registered on any public method of the managed bean through the @ EventListener annotation:
@Component public class AnnotationDrivenEventListener { @EventListener public void handleContextStart(ContextStartedEvent cse) { System.out.println("Handling context started event."); } }
As before, the method signature declares the event type it uses.
By default, listeners are invoked synchronously. However, we can easily make it asynchronous by adding the @ Async annotation. We just need to remember in the application Enable asynchronous support.
6. Generic supportYou can also use generic information in event types to schedule events.
6.1. Generic application events
Let's create a generic event type.
In our example, the event class contains anything and a success status indicator:
public class GenericSpringEvent<T> { private T what; protected boolean success; public GenericSpringEvent(T what, boolean success) { this.what = what; this.success = success; } // ... standard getters }
Note the difference between GenericSpringEvent and CustomSpringEvent. We now have the flexibility to publish arbitrary events and no longer need to extend from ApplicationEvent.
6.2. Listener
Now let's create a listener for this event.
We can define listeners by implementing the ApplicationListener interface as before:
@Component public class GenericSpringEventListener implements ApplicationListener<GenericSpringEvent<String>> { @Override public void onApplicationEvent(@NonNull GenericSpringEvent<String> event) { System.out.println("Received spring generic event - " + event.getWhat()); } }
Unfortunately, this definition requires us to inherit GenericSpringEvent from the ApplicationEvent class. Therefore, for this tutorial, let's use the annotation driven event listener discussed earlier.
You can also make event listeners conditional by defining Boolean spiel expressions on the @ EventListener annotation.
In this case, the event handler will only be called if the String object of GenericSpringEvent is successfully called:
@Component public class GenericSpringEventListener implements ApplicationListener<GenericSpringEvent<String>> { @Override public void onApplicationEvent(@NonNull GenericSpringEvent<String> event) { System.out.println("Received spring generic event - " + event.getWhat()); }
}
Spring expression language (spiel) ") is a powerful expression language, which is described in detail in another tutorial.
6.3. Publisher
The event publisher is similar to the above. However, due to type erasure, we need to publish an event to resolve the generic parameters we will filter, for example, class genericstringspringevent extensions genericspringevent < string >.
In addition, there is an alternative method to publish events. If we return a non null value as a result from a method annotated with @ EventListener, the Spring Framework will send the result to us as a new event. In addition, we can publish multiple new events by returning multiple new events to a collection as the result of event processing.
7. Transaction binding eventThis section is about using*@
TransactionalEventListener * annotation. To learn more about transaction management, see Using Spring and JPA transactions.
Starting with Spring 4.2, the framework provides a new*@
The TransactionalEventListener annotation, which is an extension of @ EventListener *, allows the listener of an event to be bound to a phase of a transaction.
You can bind to the following transaction stages:
- AFTER_COMMIT (default) - used to trigger an event when a transaction completes successfully.
- AFTER_ROLLBACK – if the transaction has been rolled back
- AFTER_COMPLETION – if the transaction is completed (alias for AFTER_COMMIT and AFTER_ROLLBACK)
- BEFORE_COMMIT - used to trigger an event before the transaction is committed.
This is a quick example of a transactional event listener:
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) public void handleCustom(CustomSpringEvent event) { System.out.println("Handling event inside a transaction BEFORE COMMIT."); }
This listener is called only if there are transactions that the event producer is running and about to commit.
If no transaction is running, the event will not be sent at all unless we override it by setting the fallbackExecution property to true.
8. ConclusionIn this short article, we introduced the basics of handling events in Spring, including creating a simple custom event, publishing it, and then handling it in a listener.
We also briefly learned how to enable asynchronous processing of events in the configuration.
Then we looked at the improvements introduced in Spring 4.2, such as annotation driven listeners, better generic support, and event binding to the transaction phase.
As usual, the code provided in this article can be found in On GitHub get. This is a Maven based project, so it should be easy to import and run.