Mastering Spring @EventListener: From Demo to Deep Debugging
This article walks through building a Spring @EventListener demo, explains how to decouple registration logic, shows step‑by‑step debugging of the event‑listener infrastructure, and explores the internal mechanisms that register and invoke listeners during application startup and runtime.
Hello, I'm Su San.
Recently I noticed a colleague using the @EventListener annotation in a project. I knew its purpose but not how it worked internally, so I decided to investigate to avoid future confusion.
Demo
First, we create a simple demo. Suppose the requirement is to send an SMS after a user successfully registers.
Typical pseudo‑code would be:
boolean success = userRegister(user);
if (success) {
sendMsg("Your registration succeeded. Come play with us!");
}This code tightly couples SMS sending with registration. To decouple, we should publish a "user registration success" event after registration:
boolean success = userRegister(user);
if (success) {
publishRegisterSuccessEvent(user);
}Listeners can then handle the SMS sending, allowing future changes (e.g., email, multiple notifications) without touching the registration logic.
We use Spring's ApplicationListener to achieve this. The demo uses Spring 5.2.10.
First, define an event class to hold relevant data:
@Data
public class RegisterSuccessEvent {
private String userName;
public RegisterSuccessEvent(String userName) {
this.userName = userName;
}
}Next, create a listener:
@Slf4j
@Component
public class RegisterEventListener {
@EventListener
public void handleNotifyEvent(RegisterSuccessEvent event) {
log.info("Detected user registration event: {}. You have registered successfully, come play!", event.getUserName());
}
}Publish the event via an HTTP endpoint:
@Resource
private ApplicationContext applicationContext;
@GetMapping("/publishEvent")
public void publishEvent() {
applicationContext.publishEvent(new RegisterSuccessEvent("WaiWai"));
}Running the service and invoking the endpoint produces the expected output with only a dozen lines of code.
Debug
When debugging, the first breakpoint should be set on the listener method.
During service startup, many framework listeners trigger, so breakpoints may hit unrelated code. To avoid this, disable breakpoints during startup or use conditional breakpoints that only stop when the event payload is an instance of RegisterSuccessEvent:
event instanceof PayloadApplicationEvent && (((PayloadApplicationEvent) event).payload instanceof RegisterSuccessEvent)
After setting the conditional breakpoint, the debugger stops exactly where the custom listener is invoked.
Further Thinking
Understanding the full flow requires knowing when ApplicationListenerMethodAdapter is created. Spring calls EventListenerMethodProcessor#afterSingletonsInstantiated during container refresh, which scans beans for @EventListener methods, constructs the adapter, and registers it.
The adapter’s constructor sets fields such as beanName, method, and declaredEventTypes. This occurs after the Spring context refreshes, linking the listener to the bean.
Details
The event publishing process is serial by default; a long‑running listener can block others. Enabling an async executor makes listeners run in parallel.
Additional @EventListener attributes (e.g., condition, phase) and the related TransactionalEventListener allow more fine‑grained control, but they are beyond the scope of this article.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
