Detailed Explanation of @EventListener

Arvind Kumar
3 min readDec 11, 2024

The @EventListener annotation in Spring Framework is used to handle events in an application. This can be applied to methods in any Spring-managed component to listen for specific application events, both predefined and custom.

https://youtube.com/@codefarm0

It is part of the Spring event-driven programming model, which promotes loose coupling between components. You can leverage @EventListener to react to certain actions or changes within your application, such as a user registration, order placement, or application startup.

Key Features of @EventListener

  1. Event-Driven Architecture: Facilitates decoupled communication between components.
  2. Handles Custom and Built-In Events: Works with predefined Spring events (ContextRefreshedEvent, ApplicationReadyEvent, etc.) or user-defined events.
  3. Asynchronous Handling: Can be combined with @Async for non-blocking event processing.
  4. Conditional Listening: Use SpEL (Spring Expression Language) with condition attribute to listen based on conditions.

Example Use Cases of @EventListener

1. Custom Event Handling

When a user registers, trigger an event to send a welcome email.

// Custom Event Class
public class UserRegisteredEvent {
private final String username;

public UserRegisteredEvent(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
}
// Event Publisher
@Component
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void registerUser(String username) {
// Perform registration logic here...
System.out.println("User registered: " + username);
// Publish event
eventPublisher.publishEvent(new UserRegisteredEvent(username));
}
}
// Event Listener
@Component
public class WelcomeEmailService {
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
System.out.println("Sending welcome email to: " + event.getUsername());
}
}
// Controller to trigger the event
@RestController
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/register")
public String registerUser(@RequestBody String username) {
userService.registerUser(username);
return "User Registered!";
}
}

2. Built-In Event Handling

Automatically perform an action when the application starts, like initializing resources.

@Component
public class StartupListener {
@EventListener(ApplicationReadyEvent.class)
public void onApplicationReady() {
System.out.println("Application is ready! Performing startup tasks...");
}
}

3. Asynchronous Event Handling

If the event handling process is time-consuming, use @Async for non-blocking execution.

@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public Executor taskExecutor() {
return new SimpleAsyncTaskExecutor();
}
}

@Component
public class NotificationService {
@Async
@EventListener
public void sendNotification(UserRegisteredEvent event) {
System.out.println("Processing notification for user: " + event.getUsername());
// Simulate delay
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Notification sent for: " + event.getUsername());
}
}

4. Conditional Listening

Handle events based on specific conditions using the condition attribute.

@Component
public class AdminNotificationService {
@EventListener(condition = "#event.username == 'admin'")
public void notifyAdmin(UserRegisteredEvent event) {
System.out.println("Special handling for admin user: " + event.getUsername());
}
}

More complex conditional examples

@EventListener(condition = "#event.user=='arvind'")     // Equality
@EventListener(condition = "#event.user!='arvind'") // Inequality
@EventListener(condition = "#event.age > 18") // Greater than
@EventListener(condition = "#event.age >= 18") // Greater than or equal
@EventListener(condition = "#event.age < 18") // Less than
@EventListener(condition = "#event.age <= 18") // Less than or equal
@EventListener(condition = "#event.user matches 'ar.*'") // Regex match
@EventListener(condition = "#event.role.equals('ADMIN')") // Object equality

// Logical operators
@EventListener(condition = "#event.age > 18 and #event.user=='arvind'") // AND
@EventListener(condition = "#event.age > 18 or #event.user=='arvind'") // OR
@EventListener(condition = "!#event.isDeleted") // NOT

// Collection operations
@EventListener(condition = "#event.roles.contains('ADMIN')") // Contains
@EventListener(condition = "#event.tags.size() > 0") // Size check

// Null checks
@EventListener(condition = "#event.user != null") // Not null

@EventListener(condition = "#event.user?.length() > 5") // Safe navigation
@EventListener(condition = "#event instanceof T(com.example.AdminEvent)") // Type check
@EventListener(condition = "#event.timestamp > T(java.time.Instant).now().minusSeconds(3600)") // Time comparison

Benefits of Using @EventListener

  • Decoupling: Event publishers and listeners don’t depend on each other, promoting better modularity.
  • Flexibility: Listeners can act on multiple types of events, reducing repetitive code.
  • Scalability: With asynchronous event processing, applications can handle multiple events without blocking.

— — — -

Liked this article? If Yes follow me and subscribe to the codefarm YouTube channel.

--

--

Arvind Kumar
Arvind Kumar

Written by Arvind Kumar

Staff Engineer @Chegg || Passionate about technology || https://youtube.com/@codefarm0

No responses yet