Spring Events: Decouple Your Application with @EventListener and ApplicationEvents
Author
Marcus HeldIf you’re already working with the Spring Framework, you’ve undoubtedly recognized its power and versatility. One of the valuable - yet often overlooked - features of Spring is its event-handling system. In this article, we’ll delve deeper into how you can configure events in the Spring Framework using @EventListener
. Moreover, we’ll illustrate how these events can be paired with transactions and asynchronicity.
Why Events in the Spring Framework?
Events are an integral component of the Spring Framework. They allow for the creation of loosely coupled applications. Spring Boot employs events to communicate the application’s status. An example of this is the ApplicationStartedEvent
. However, you can also publish your own events. And this is possible out-of-the-box, without boilerplate and with minimal effort.
What is an Event?
An event in Spring, often referred to as an ApplicationEvent, is simply a signal indicating that something has transpired in the application. This signal can then be captured by one or multiple listeners that respond to it. With ApplicationEvents, the Observer or Publish-Subscribe Pattern described by the ‘Gang of Four’ in their renowned book on Design Patterns is implemented.
ApplicationEvent
interface, and a listener had to implement the ApplicationListener
interface. In this article, we focus on the contemporary approach with the @EventListener
annotation and POJOs.Every Java Object Can Be an Event
With the Spring Framework, declaring an event is straightforward. Any class can be an event. There’s no limitation; simply write a Plain Old Java Object (POJO) and, for easy handling, keep it immutable.
class CustomSpringEvent {
private String parameter;
public CustomSpringEvent(String parameter) {
this.parameter = parameter;
}
}
Publish an Event Using ApplicationEventPublisher
Spring Boot automatically registers an ApplicationEventPublisher
bean. You can inject this into your services and use it to publish your event.
@Service
public class SomeService {
private final ApplicationEventPublisher eventPublisher;
public SomeService(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void someMethod() {
eventPublisher.publishEvent(new CustomSpringEvent());
}
}
Receive an Event with @EventListener
Once you’ve published your event, you can receive it in any Spring-managed bean using the @EventListener
annotation.
@EventListener
public void handleCustomEvent(CustomSpringEvent event) {
// Some logic
}
Events and Transactions
Handling events and transactions can sometimes be tricky. Fortunately, Spring offers the @TransactionalEventListener
annotation to simplify this.
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(CustomSpringEvent event) {
// Some logic
}
In this example, the event listener is executed only after the transaction, which triggered the event, has been committed.
TransactionPhase.AFTER_COMMIT
is the default phase and thus doesn’t need explicit declaration. Other alternatives include BEFORE_COMMIT
, AFTER_ROLLBACK
, and AFTER_COMPLETION
.Asynchronous Events
@Async
can be combined with @EventListener
. This results in the event being processed in a separate thread.
@EventListener
@Async
public void handleAsyncEvent(CustomSpringEvent event) {
System.out.println("Handled event asynchronously: " + event.getMessage());
}
Spring ApplicationEvents Decouple Your Modules
With event-driven architectures, you can decouple your modules from each other. Spring Application Events assist in accomplishing this. In a later development phase and once the need arises, an application using Application Events can easily transition to Spring Integration and external Message Queues.