Spring Events

Introduction to Spring Events

In this post, we will cover Spring Events which is a way to loosely couple component in your application for better design and easy exchange of information.

 

1. Introduction

Spring framework events are part of the Spring Framework, however, I believe that this is one of the most overlooked features of the Spring Framework. Spring events provide a lot of features and capabilities and one of the most interesting among those are event publishing provided by ApplicationContext. Application events are not used that frequently in the real world application, however, Spring Framework internally use a lot of these events to communicate various states, with Spring Boot, it has become more interesting.

Spring 4.1 introduced @EventListener,  annotation driven event Listener which removed all the complexities of defining your EventListner.@EventListener is a core annotation handled transparently in a similar fashion as @Autowired and others: no extra configuration is necessary with java config

 

2. Custom Spring Events

To understand it more, we will create and publish a custom Spring event. Spring provides flexibility to create and publish custom events which by default will be synchronous. We will work on a simple example of customer registration, we will publish a simple CustomerRegistration event whenever a new customer registers with our application. We will let all listeners handle this event and perform applicable action (e.g. sending email on customer registrations)

2.1 Custom Events

In this example, we will create a simple CustomerRegistrationEvent to store customer data (in our case just customer name)

public class CustomerRegistrationEvent {

    private String name;

    public CustomerRegistrationEvent(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

Before Spring 4.2, it required us to extend ApplicationEvent which is no longer required. This change has its own merits as it is much easier to publish events while it’s hard to trek events in large applications.

 

2.2 Custom Events Listener

As part of our example, we need a listener which should listen to the event being published and act accordingly in case event published by the service is of interest.

 

@Component
public class CustomerRegistrationEventListener {

    @EventListener
    void handleRegistration(CustomerRegistrationEvent event){
        System.out.println("Registration event got triggered for customer::  " + event.getName());
    }
}

 

With Spring 4.2, it does not require you to implement ApplicationListener or something similar but a simple @EventListener annotation suffices to declare it as a Listener.

Spring will create an ApplicationListener instance for the event with a type taken from the method argument. There is no limitation on the number of annotated methods in one class–we can group all related event handlers into one class.

 

2.3 Publishing Events

We will create a publisher with following tasks:

  1. It will create an event object.
  2. It will publish that event to all who are listening to this event.

We need ApplicationEventPublisher in our code to publish given event.

@Autowired
private ApplicationEventPublisher publisher;

public void publishEvent(final String name) {
    publisher.publishEvent(new CustomerRegistrationEvent(name));
}

 

3. Async Events

As mentioned earlier, these events work in Async mode, which means publisher thread will block until all the listeners (who are listing to this event) have finished processing this event.This can lead to a certain issue in terms of application scaling where we want to run these events in Async mode and let rest of the application to work normally.To allow Spring to handle events asynchronously, we need to redefine ApplicationEventMulticaster with an executor.

@Bean(name = "applicationEventMulticaster")
ApplicationEventMulticaster applicationEventMulticaster() {
    SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
    eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
    eventMulticaster.setErrorHandler(TaskUtils.LOG_AND_SUPPRESS_ERROR_HANDLER);
    return eventMulticaster;
}

This will enable asynchronously mode at the global level (at the ApplicationContext level), this means that all method annotated with @EventListener will be executed asynchronously.

Another most easier way is to use @Async annotation

@Async
@EventListener
void handleRegistration(CustomerRegistrationEvent event){
    System.out.println("Registration event got triggered for customer::  " + event.getName());
}

We need to make to enable asynchronous method execution by enabling @EnableAsync

 

4. Filtering

We can also use condition attribute on our listener to filter certain events. Let’s say we want to listen to only CustomerRegistration event if this is a B2B customer.

 

@EventListener(condition = "#event.customerType=B2C")
void handleRegistration(CustomerRegistrationEvent event){
    System.out.println("Registration event got triggered for customer::  " + event.getName());
}

 

5. Transaction bound events

Spring provides a way to bound events to a certain phase of a transaction (e.g. publish an event when a transaction is complete). We can use @TransactionalEventListener annotation to achieve this behavior. When @TransactionalEventListener is present, Spring will automatically register this in place of default one.

To put it in simple words, this Listener will only invoke if there is a transaction running, in case of no running transaction, it will not invoke this at all.

 

Summary

In this post, we got an introduction to Spring framework events. We learned how we can create custom events and how to use publish Spring events synchronously and asynchronously. We briefly covered how to use a condition to filter events and transaction capabilities of the Spring Framework event system.

Umesh

Hello!! I am Umesh- an engineer by profession and a photographer by passion.I like to build stuff on the web using OSS and love to capture the world through my lens.

follow me on:

2
Leave a Reply

avatar
1 Comment threads
1 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
2 Comment authors
Umesh AwasthiNikola Recent comment authors

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
newest oldest most voted
Notify of
Nikola
Guest
Nikola

“…Async mode, which means publisher thread will block until all the listeners … have finished processing this event.”

That’s definition of “Sync”, not “Async”

Umesh Awasthi
Admin
Umesh Awasthi

Agree Nikola!! but this line highlight the issue with the Sync mode and why we need the Async mode.This line is to set the context as why we have the need to look for the Async mode.