Wednesday, June 9, 2021

Event Handling in Spring

Suppose you are working on a Order Management system. Once the order is placed, the  system needs to do the following taks:

1. Send email notification to customer

2. Send request to Payment processing system to make payment.

Generally, in traditional way of programming, once the order is placed we call below 2 methods:

sendEmailToCustomer()

makePayment()

Now suppose , the product owner gives you a requirement to send email notification to seller also once the order is placed. To do that, now you need to introduce another method, sendEmailToSeller, along with the above 2 methods.

This approach has a drawback. If the order is created from multiple places, we need to introduce this change in all these places.

We can handle the same problem in event driven approch. We can consider Order creation as an event; hence it becomes a producer for event & sending email to cutomer , making payment & sending email to Seller become the event consumers.

Spring framework comes with an in-built support for Event Driven processing. It requires 3 elemts for an event:

1. the Event itself

2. Pulisher of the event

3. Consumer/Listener of the event

All of these are handled in Spring framework in an elegant way. 

Prerequisite: 

Java 8

Spring framework version: 4.3.30.RELEASE

Maven dependency:

                <dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-core</artifactId>

<version>4.3.30.RELEASE</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>4.3.30.RELEASE</version>

</dependency>

Event: The event can be any Java Bean model class; for brevity have removed the getters & setters. You can add @Getter & @Setter annotation from lombok library also.

public class OrderEvent {

private String itemName;

private int quantity;

}

Event Publisher: Spring comes with an in built ApplicationEventPublisher class defined in org.springframework.context.ApplicationEventPublisher.

You can publish the event like below: 

@Service

public class OrderEventProducer {

@Autowired

private ApplicationEventPublisher publisher;

public void publishTestEvent() {

OrderEvent order = new OrderEvent();

order.setItemName("Pen");

order.setQuantity(5);

System.out.println("Puslishing order");

publisher.publishEvent(order);

}

}

Event Listener: Once the event is pusblished, it can be consumed. The consumers are called EventListner. Spring comes with below features for Event listener/consumers
1. The consumer can be asynchronous , add @EnableAsync annotation at class level & the method to be processed async. way need to add @Async annotation.
2. For multiple consumers orders can be set with @Order annotation
3. Any method can be marked as event listener with  @EventListener annotation
4. The event listener method must have the same event argument in consumer method as published from ApplicationEventPublisher.

The code snippet will look like below.

@Component
@EnableAsync
public class OrderEventListener {
@Async
@EventListener
@Order(1)
public void sendEmailToCustomer(OrderEvent event) {
System.out.println("Starting email sending");
delay();
System.out.println("sendEmail:" + event);
}

@EventListener
@Order(2)
public void makePayment(OrderEvent event) {
System.out.println("makePayment:" + event);
}

private void delay() {

try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

Now, you can easily add other consumer methods for same event with OrderEvent  as parameter. No code change required at producer end.

Code Example:


Furthur Reading:


Convert Java Project from Log4j 1 to Log4j2

Many times while working on old Java projects we find Log4j 1.x is used. But as the Log4j2 is the new one; hence to upgrade to Log4j2 we nee...