About Soroosh Sarabadani

My name is Soroosh Sarabadani from Iran. I'm working more than 8 year in development and design Enterprise softwares, with master of software engineering grade.

How to use Events in Spring 3.x

There are many concepts and techniques for creating loosely coupled applications, Event is one of them. Events can eliminate many of dependencies in your code. Some times without events, SRP* is very hard to implement. Observable interface in java can help us to implement events (through Observer Pattern).

But wait, the goal of this post is a fast tutorial about Spring Event. Spring has some nice facilities for creating Event Driven Applications. You can raise a specific event in a bean and listen to it in the other bean.

Imagine a simple application with these requirements:
 

  • There are some orders that can have different status
  • when an order is in DELIVERED or POSTPONED state we need to send an email to the customer

The first (but not the best) solution for requirement satisfaction is sending email in our Order model, But There are some defects:

  • It’s not responsibility of Order to sending email.
  • If you follow Domain Driven principle, Order is a domain object but Email Sender maybe is a service ( different from Domain Service ) so you can’t use it in your model.

The other solution is raising some events in our Order model after changing its status. I’s not concern of Order what will happen after raising this event. In our example we need to listen to a specific kind of events, analyze them and do some business (Sending Email).

@Configurable
 public class Order implements ApplicationEventPublisherAware {
 private final String orderId;
 private final Date createDate;
 private final CustomerInfo customerInfo;
 private ApplicationEventPublisher eventPublisher;
 private Date lastUpdateDate;
 private Status status;
 
public Order(String orderId, CustomerInfo customerInfo) {
 this.orderId = orderId;
 this.customerInfo = customerInfo;
 status = Status.MODIFIABLE;
 this.createDate = new Date();
 this.lastUpdateDate = this.createDate;
 }
 
public String getOrderId() {
 return orderId;
 }
 
public void checkOut() {
 if (status == Status.DELIVERED) {
 throw new IllegalStateException(String.format("Order is already delivered"));
 }
 this.status = Status.CHECKED_OUT;
 this.lastUpdateDate = new Date();
 }
 
public void deliver() {
 if (this.status != Status.CHECKED_OUT && this.status != Status.POSTPONED) {
 throw new IllegalStateException(String.format("Order status should be CHECKED OUT for delivery to be called. but is : %s", status));
 }
 
this.status = Status.DELIVERED;
 this.lastUpdateDate = new Date();
 this.eventPublisher.publishEvent(new OnOrderDelivered(this));
 }
 
public void postponeDelivery() {
 if (status != Status.CHECKED_OUT && status != Status.POSTPONED) {
 throw new IllegalStateException(String.format("Can not postpone delivery in this state: %s", status));
 }
 this.status = Status.POSTPONED;
 this.lastUpdateDate = new Date();
 this.eventPublisher.publishEvent(new OnOrderPostponed(this));
 }
 
public Status getStatus() {
 return status;
 }
 
public CustomerInfo getCustomerInfo() {
 return customerInfo;
 }
 
public Date getLastUpdateDate() {
 return lastUpdateDate;
 }
 
public Date getCreateDate() {
 return createDate;
 }
 
@Override
 public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
 this.eventPublisher = applicationEventPublisher;
 }
 
public static enum Status {
 MODIFIABLE,
 CHECKED_OUT,
 POSTPONED,
 DELIVERED,
 CANCELED;
 }
 }

As you see Order is a configurable class, if you have not worked with this concept before, don’t be anguished. For this post just you need to know Configurable classes can create everywhere with new keyword but they are managed by spring, so you can inject other beans in them or use most of the spring facilities with them. I promise to post an article about it as soon as possible.

Order class implements  org.springframework.context.ApplicationEventPublisherAware interface. This interface has a setter method with name setApplicationEventPublisher that presents ApplicationEventPublisher for using in your class. As you see in deliver method we used this object to publish an event (this.eventPublisher.publishEvent(new OnOrderDelivered(this))). You can publish every event that extends org.springframework.context.ApplicationEvent. We have raised another event OnOrderPostponed when an order becomes postponed.

public abstract class OnOrderStatusChanged extends ApplicationEvent {
 private final Order order;
 
public OnOrderStatusChanged(Order source) {
 super(source);
 this.order = source;
 System.out.println(String.format("Order:%s status is changed to %s", source.getOrderId(), source.getStatus()));
 }
 
public Order getOrder() {
 return order;
 }
 }
 
public class OnOrderDelivered extends OnOrderStatusChanged {
 public OnOrderDelivered(Order order) {
 super(order);
 }
 }
 
public class OnOrderPostponed extends OnOrderStatusChanged {
 public OnOrderPostponed(Order order) {
 super(order);
 }
 }

OnOrderStatusChanged is an abstract class what OnOrderDelivered and OnOrderPostponed extends it. until now we could create our events and raise them. now if you create a spring test and call deliver method of an order you will see “Order:X status is changed to DELIVERED” The last step is doing something when these events published. we want to send an email to the customer when these method raised. additionally it’s valuable for customer to posting the product when his order is in delivered state. Listeners are simple Beans that implements generic ApplicationListener interface. Parameter type in this interface is the type of event that you want to listen to it. it is possible to defince parameter type as the parent and listen to all of its childres. for example in our model if we use OnOrderStatusChanged our listener will catch all event from OnOrderDelivered and OnOrderPostponed

It can be suitable for sending email in our scenario. but we don’t use this model and create two different listener for them.

As you see below their code is very simple

@Service
 public class OrderDeliveredEmailSender implements ApplicationListener,Ordered {
 
@Override
 public void onApplicationEvent(OnOrderDelivered event) {
 System.out.println(String.format("Message sent for delivered order to:%s ORDER-ID:%s",event.getOrder().getCustomerInfo().getEmail(),event.getOrder().getOrderId()));
 }
 
@Override
 public int getOrder() {
 return 100;
 }
 }
 
@Service
 public class OrderPostponedEmailSender implements ApplicationListener {
 
@Override
 public void onApplicationEvent(OnOrderPostponed event) {
 System.out.println(String.format("Message sent for postponed order to:%s ORDER-ID:%s", event.getOrder().getCustomerInfo().getEmail(), event.getOrder().getOrderId()));
 }
 }

These two beans will fire onApplicationEvent when  correspond event is raised. For posting product to the customer we need to create another Listener for OnOrderDelivered event.

@Service
 public class OnOrderDeliveredPost implements ApplicationListener,Ordered {
 @Override
 public void onApplicationEvent(OnOrderDelivered onOrderDelivered) {
 System.out.println(String.format("Order:%s is posting for customer.",onOrderDelivered.getOrder().getOrderId()));
 }
 
@Override
 public int getOrder() {
 return 1000;
 }
 }

As you see this listener will send product to the customer when its state is DELIVERED. But wait there what is Ordered interface? if you have not use org.springframework.core.Ordered interface, it is valuable to know that with using this interface you can define the order between beans in a collection. in our scenario customer like to receive an email before we post the product to him. for this purpose these two class implement Ordered interface, don’t forget the lowest order has the highest priority.

*Single Responsibility Principle

 

Reference: How to use Events in Spring 3.x from our JCG partner Soroosh Sarabadani at the Just another Java blog 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 two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

2 Responses to "How to use Events in Spring 3.x"

  1. Kristianto Yanuar says:

    Very nice article! Very helpful!

  2. Jety says:

    Thank you very much, man, I am going to implement Spring event firing/listening and the information you have here is exactly what I need.

Leave a Reply


eight + 4 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close