Detailed Explanation of @EventListener
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.
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
- Event-Driven Architecture: Facilitates decoupled communication between components.
- Handles Custom and Built-In Events: Works with predefined Spring events (
ContextRefreshedEvent
,ApplicationReadyEvent
, etc.) or user-defined events. - Asynchronous Handling: Can be combined with
@Async
for non-blocking event processing. - 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.