<

I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE COURSE

1. Overview

In this article we’ll be discussing how to use events in Spring.

Event are one of the more overlooked functionalities in the framework but also one of the more useful. And – like many other things in Spring – event publishing is one of the capabilities provided by ApplicationContext.

There are a few simple guidelines to follow:

  • the event should extend ApplicationEvent
  • the publisher should inject an ApplicationEventPublisher object
  • the listener should implement the ApplicationListener interface

2. A Custom Event

Spring allows to create and publish custom events which – by default – are synchronous. This has a few advantages – such as, for example the listener being able to participate in the publisher’s transaction context.

2.1. A Simple Application Event

Let’s create a simple event class – just a placeholder to store the event data. In this case, the event class holds 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. A Publisher

Now let’s create a publisher of that event. The publisher constructs the event object and publishes it to anyone who’s listening.

To publish the even, the publisher can simply inject the ApplicationEventPublisher and use the publishEvent() API:

public class CustomSpringEventPublisher {
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    public void doStuffAndPublishAnEvent(final String message) {
        System.out.println("Publishing custom event. ");
        CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
        applicationEventPublisher.publishEvent(customSpringEvent);
    }
}

Alternatively, the publisher class can implement the ApplicationEventPublisherAware interface – this will also inject the event publisher on the application start-up. Usually, it’s simpler to just inject the publisher with @Autowire.

2.3. A Listener

Finally, let’s create the listener.

The only requirement for the listener is to be a bean and implements 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 is parametrized with the generic type of custom event – which makes the onApplicationEvent() method type safe. This also avoids having to check if the object is an instance of specific event class and casting it.

And, as already discussed – by default spring events are synchronous – the doStuffAndPublishAnEvent() method blocks until all listeners finish processing the event.

3. Creating Asynchronous Events

In some cases, publishing events synchronously isn’t really what we’re looking for – we may need async handling of our events.

You can turn that on in the configuration by creating a ApplicationEventMulticaster bean with an executor; for our purposes here SimpleAsyncTaskExecutor works well:

@Configuration
public class AsynchronousSpringEventsConfig {
    @Bean(name = "applicationEventMulticaster")
    public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
        SimpleApplicationEventMulticaster eventMulticaster 
          = new SimpleApplicationEventMulticaster();
        
        eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
        return eventMulticaster;
    }
}

The event, the publisher and the listener implementations remain the same as before – but now, the listener will asynchronously deal with the even in a separate thread.

4. Existing Framework Events

Spring itself publishes a variety of events out of the box. For example, the ApplicationContext will fire various framework events. E.g. ContextRefreshedEvent, ContextStartedEvent, RequestHandledEvent etc.

These events provide application developers an option to hook into the lifecycle of the application and the context and add in their own custom logic where needed.

Here’s a quick example of a listener listening for context refreshes:

public class ContextRefreshedListener 
  implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent cse) {
        System.out.println("Handling context re-freshed event. ");
    }
}

5. Conclusion

In this quick tutorial we went over the basics of dealing with events in Spring – creating a simple, custom event, pushing it and then handling it in a listener. We also had a brief look at how to enable asynchronous processing of events in the configuration.

I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE LESSONS

  Subscribe  
newest oldest most voted
Notify of
Naresh
Guest
Naresh

Might be silly question… If we are using synchronous event and I published event from a transactional service… Then event handler will also take part in same transaction right?

Eugen Paraschiv
Guest

Hey Naresh – not a silly question at all. When the async method is called – no, the transactional context will not be propagated – it will be executed outside of the transaction. Hope that clarifies things. Cheers,
Eugen.

Koushik Chatterjee
Guest
Koushik Chatterjee

Hi Eugen, so is there any way so that I can run some of the event async and some sync way by using annotation based configuration. assume (i have multiple event publisher, for same or multiple event)

Eugen Paraschiv
Guest

That’s definitely a good question. I don’t think that’s supported, but I haven’t checked lately. Now, there is of course another way to go here – you can make use of the @Async annotation to make sure the events that should be handled in an async way, are.
Hope it helps. Cheers,
Eugen.

Aleksandar Milicevic
Guest
Aleksandar Milicevic

Hi Eugen,
Can I inject spring bean to custom spring event?

Eugen Paraschiv
Guest

Hey Aleksandar – so, if you mean injecting a bean into the actual event – no, that’s not something I’d recommend. That would mean that the actual event needs to be a Spring bean, which makes events heavyweight and ads conceptual load to your system. If you really need to pass a bean reference, that’s fine – you can certainly do that when you instantiate your event (again, if you really need to). But most of the time, you shouldn’t need to do that.
Hope that helps. Cheers,
Eugen.