1. What is a Spring Event?
Spring provides a built-in event-driven programming model that allows different parts of your application to communicate without being tightly coupled.
An event in Spring is an object that carries information about something that has happened, and it is published to notify interested listeners.
Examples:
- User registered → send a welcome email
- Order placed → reduce stock, send notification
- File uploaded → trigger background processing
This is based on the Observer design pattern, where publishers don’t know who listens, and listeners don’t care who publishes.
2. How does it work?
The workflow looks like this:
- Event creation
-
A class extending
ApplicationEvent
(or any custom POJO since Spring 4.2).- Event publishing
-
Use
ApplicationEventPublisher
to publish events.- Event listening
-
Create a listener using
@EventListener
(orApplicationListener
).- Event handling
Spring’s
ApplicationEventMulticaster
dispatches the event to listeners.
3. When and When Not to Use It?
When to use:
- To decouple business logic. Example: a user service should not know how notifications or emails are handled.
- For side effects after main actions (logging, auditing, sending alerts).
- For extensibility, where other modules can subscribe without modifying the core logic.
When not to use:
- For core business workflows where ordering and transaction boundaries are critical.
- For synchronous dependencies that must always run. Example: payment → order confirmation → invoice. These should be service calls, not events.
- For complex orchestration. Consider messaging solutions (Kafka, RabbitMQ, etc.) instead.
4. How to Create and Publish an Event
Example Domain: User Registration
a) Create an Event (Custom POJO)
public class UserRegisteredEvent {
private final String email;
public UserRegisteredEvent(String email) {
this.email = email;
}
public String getEmail() {
return email;
}
}
b) Publish an Event (Same Thread)
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final ApplicationEventPublisher publisher;
public UserService(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void registerUser(String email) {
// main logic
System.out.println("User registered: " + email);
// publish event
publisher.publishEvent(new UserRegisteredEvent(email));
}
}
Note: By default, events are synchronous. The publisher and listener run in the same thread.
c) Publish an Event (Different Thread – Asynchronous)
Enable async event handling:
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync
public class AsyncConfig {
}
Use @Async
on listener:
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class EmailListener {
@Async
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
System.out.println("Sending email to: " + event.getEmail());
}
}
Now, the email sending runs on a separate thread (from Spring’s async executor pool).
5. How to Catch an Event
There are two main approaches:
a) Using @EventListener
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class WelcomeEmailListener {
@EventListener
public void onUserRegistered(UserRegisteredEvent event) {
System.out.println("Welcome email sent to: " + event.getEmail());
}
}
b) Using ApplicationListener
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class AuditLogListener implements ApplicationListener<UserRegisteredEvent> {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
System.out.println("Audit log: User registered with email " + event.getEmail());
}
}
Summary
- Spring Events help decouple components using an event-driven approach.
- Publisher fires events, and listeners react to them.
- Events are synchronous by default but can be made asynchronous with
@Async
. - Use them for side effects, extensibility, and decoupling, but avoid them in core transactional workflows.
Top comments (0)