VOOZH about

URL: https://www.javacodegeeks.com/2015/10/annotation-driven-event-listeners-in-spring-4-2-2.html

⇱ Annotation-driven event listeners in Spring 4.2 - Java Code Geeks


Introduction

Exchanging events within the application has become indispensable part of many applications and thankfully Spring provides a complete infrastructure for transient events (*). The recent refactoring of transaction bound events gave me an excuse to check in practice the new annotation-driven event listeners introduced in Spring 4.2. Let’s see what can be gained.

(*) – for persistent events in Spring-based application Duramen could be a solution that is worth to see

The old way

To get a notification about an event (both Spring event and custom domain event) a component implementing ApplicationListener with onApplicationEvent has to be created.

@Component
class OldWayBlogModifiedEventListener implements
 ApplicationListener<OldWayBlogModifiedEvent> {

 (...)

 @Override
 public void onApplicationEvent(OldWayBlogModifiedEvent event) {
 externalNotificationSender.oldWayBlogModified(event);
 }
}

It works fine, but for every event a new class has to be created which generates boilerplate code.

In addition our event has to extend ApplicationEvent class – the base class for all application events in Spring.

class OldWayBlogModifiedEvent extends ApplicationEvent {

 public OldWayBlogModifiedEvent(Blog blog) {
 super(blog);
 }

 public Blog getBlog() {
 return (Blog)getSource();
 }
}

Please notice that using domain objects in the events has notable drawback and is not the best idea in many situations. Pseudodomain objects in the code examples were used to not introduce unnecessary complexity.

Btw, ExternalNotificationSender in this example is an instance of a class which sends external notifications to registered users (e.g. via email, SMS or Slack).

Annotation-driven event listener

Starting with Spring 4.2 to be notified about the new event it is enough to annotate a method in any Spring component with @EventListener annotation.

@EventListener
 public void blogModified(BlogModifiedEvent blogModifiedEvent) {
 externalNotificationSender.blogModified(blogModifiedEvent);
 }

Under the hood 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 – all related event handlers can be grouped into one class.

Conditional event handling

To make @EventListener even more interesting there is an ability to handle only those events of a given type which fulfill given condition(s) written in SpEL. Let’s assume the following event class:

public class BlogModifiedEvent {

 private final Blog blog;
 private final boolean importantChange;

 public BlogModifiedEvent(Blog blog) {
 this(blog, false);
 }

 public BlogModifiedEvent(Blog blog, boolean importantChange) {
 this.blog = blog;
 this.importantChange = importantChange;
 }

 public Blog getBlog() {
 return blog;
 }

 public boolean isImportantChange() {
 return importantChange;
 }
}

Please note that in the real application there would be probably a hierarchy of Blog related events.
Please also note that in Groovy that class would be much simpler.

To generate event only for important changes the condition parameter can be used:

@EventListener(condition = "#blogModifiedEvent.importantChange")
 public void blogModifiedSpEL(BlogModifiedEvent blogModifiedEvent) {
 externalNotificationSender.blogModifiedSpEL(blogModifiedEvent);
 }

Relaxed event type hierarchy

Historically ApplicationEventPublisher had only an ability to publish objects which inherited after ApplicationEvent. Starting with Spring 4.2 the interface has been extended to support any object type. In that case the object is wrapped in PayloadApplicationEvent and sent through.

//base class with Blog field - no need to extend `ApplicationEvent`
class BaseBlogEvent {}

class BlogModifiedEvent extends BaseBlogEvent {}
//somewhere in the code
ApplicationEventPublisher publisher = (...); //injected

publisher.publishEvent(new BlogModifiedEvent(blog)); //just plain instance of the event

That change makes publishing events even easier. However, on the other hand without an internal conscientiousness (e.g. with marker interface for all our domain events) it can make event tracking even harder, especially in larger applications.

Publishing events in response to

Another nice thing with @EventListener is the fact that in a situation of non-void return type Spring will automatically publish returned event.

@EventListener
 public BlogModifiedResponseEvent blogModifiedWithResponse(BlogModifiedEvent blogModifiedEvent) {
 externalNotificationSender.blogModifiedWithResponse(blogModifiedEvent);
 return new BlogModifiedResponseEvent(
 blogModifiedEvent.getBlog(), BlogModifiedResponseEvent.Status.OK);
 }

Asynchronous event processing

Updated. As rightly suggested by Radek Grębski it is also worth to mention that @EventListener can be easily combined with @Async annotation to provide asynchronous event processing. The code in the particular event listener doesn’t block neither the main code execution nor processing by other listeners.

@Async //Remember to enable asynchronous method execution 
 //in your application with @EnableAsync
 @EventListener
 public void blogAddedAsync(BlogAddedEvent blogAddedEvent) {
 externalNotificationSender.blogAdded(blogAddedEvent);
 }

To make it work it is only required to enable asynchronous method execution in general in your Spring context/application with @EnableAsync.

Summary

Annotation-driven event listeners introduced in Spring 4.2 continue a trend to reduce boilerplate code in Spring (Boot) based applications. The new approach looks interesting especially for small applications with a small amount of events where a maintenance overhead is lower. In the world of ubiquitous Spring (Boot) magic it is more worthy to remember that with great power comes great responsibility.

In the next blog post I will write how the new mechanism can be also used to simplify handling of transaction bound events.

Please note that Spring Framework 4.2 is a default dependency of Spring Boot 1.3 (at the time of writing 1.3.0.M5 is available). Alternatively it is possible to manually upgrade Spring Framework version in Gradle/Maven for Spring Boot 1.2.5 – it should work for most of the cases.

Reference: Annotation-driven event listeners in Spring 4.2 from our JCG partner Marcin Zajaczkowski at the Solid Soft blog.
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Thank you!

We will contact you soon.

Tags
Spring
👁 Photo of Marcin Zajaczkowski
Marcin Zajaczkowski
October 1st, 2015Last Updated: October 1st, 2015
1 133 3 minutes read

Marcin Zajaczkowski

Marcin is an experienced architect who specializes in creating high quality software. Being under the impression of the Agile methodologies and the Software Craftsmanship movement, he believes in the value of good, testable and maintainable code. He aims to forge good software that makes the client delighted and the team proud of how the code itself looks.In his teaching, as a conference speaker, college lecturer, IT coach and trainer, he shows how to guide software development effectively using tests (with TDD, pair programming, Clean Code, design patterns, etc.) and maintaining a quality-oriented development environment (with CI, Sonar, automatic deployment, etc.).He is also a FOSS projects author and contributor, a Linux enthusiast.
Subscribe

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

1 Comment
Oldest
Newest Most Voted
Zayden
9 years ago

Hi, Great tutorial.

I have a question, would it be possible to implement this across two applications? One publishing the event and the other subscribing/consuming?

Regards
Zayden

0
Reply
Back to top button
Close
wpDiscuz