Skip to content

Async and Filtering Events 🚦

Lyes S edited this page Jul 10, 2022 · 4 revisions

Table Of Contents

Implementing Asynchronous Events

By default, Spring events are synchronous, meaning that the publisher thread blocks until all listeners interested in a particular event have finished processing the event.

What if we have a listener that takes too long to get executed an publishing synchronously ?

Ref.:[1]

The solution is to make the event listener running in Async mode. To do so, we have to annotate the listener with @Async annotation ( @EnableAsync is required on top of the Spring configuration).

Please note that, the usage of @Async comes with its limitations :

  • Cannot publish event by returning value.
    • Use ApplicationEventPublisher.publish() if any.
  • Exceptions are not propagated to the caller.
    • Use AsyncUncaughExceptionHandler interface if any.

External Analytics System Use Case

An external call is really slow and it doesn't make sense to block the whole use case. Executing this call as an event asynchronously is the best approach.

Ref.:[1]
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class AnalyticsCustomerRegisteredListener {
    
    private final AnalyticsService analyticsService;

    @EventListener
    @Async
    public void onRegisterEvent(CustomerRegisteredEvent event) {
        analyticsService.registerNewCustomer(event.getCustomer());

    }
}

Filtering Events

Let say we want an event listener to be triggered only if some condition is satisfiable. The intuitive solution is to add an if statement to check a certain condition.

public class MyListener {

    @EventListener
    public void onEvent(Object o) {
        if(condition) {..}
    }
}

However, overusing conditionals statement results in code that is more complex and difficult to maintain.

We can avoid this by fine-tuning those conditions with @EventListener and Spring Expression Language (SpEL).

@EventListener provides a conditional attribute that accepts SpEL expression. The event will be handled if the expression evaluates :

  • The 'Boolean' : true
  • One of Strings : "true", "on", "yes", "1"
  • The default expression is empty String : "" (meaning the event is always handled)

Examples

  • #event : reference to an event
  • #event.customer.type eq 'b2c'

In the following use case, the purpose is to run a promotion for all new customers who have signed up for the newsletter.

import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class PromotionListeners {

    private final PromotionService promotionService;

    @EventListener(condition = "#event.customer.newsletter")
    public void onRegistrationEvent (CustomerRegisteredEvent event) {
        promotionService.applyPromotion(event.getCustomer());
    }
}
Clone this wiki locally