Key Considerations and Best Practices for Using Spring Event in Backend Systems
This article explains critical pitfalls and best‑practice guidelines for employing Spring Event in Java backend applications, covering graceful shutdown requirements, event loss during startup, suitable business scenarios, reliability enhancements, retry mechanisms, idempotency, and the relationship between Spring Event and message queues.
Today we focus on the most critical issues when using Spring Event, based on valuable experience from production incidents.
1. Why must a business system implement graceful shutdown before using Spring Event?
When Spring broadcasts an event, it looks for listeners in the ApplicationContext by retrieving bean instances. However, during the shutdown of the ApplicationContext , calling getBean is prohibited and will cause an error.
This knowledge point was hard‑won after a production failure; it must be taken seriously.
We recently saw logs indicating that a bean could not be found during a destroy method, with the stack trace containing the message:
Do not request a bean from a BeanFactory in a destroy method implementation
During context shutdown, beans must not be retrieved. In high‑traffic services, a small amount of traffic may still arrive during shutdown, causing Spring Event publishing to fail and resulting in exceptions.
Therefore, before using Spring Event, ensure that the service cuts off inbound traffic (HTTP, MQ, RPC) before the Spring context is closed.
2. Why are events lost during the service startup phase?
In our case, a Kafka consumer started in the init-method phase, but the EventListener registration occurred later, after the init-method . Consequently, events published by the consumer could not find listeners and were lost.
The diagram shows that the init-method timing lags behind the listener registration.
Spring Boot only opens HTTP traffic after the application is fully started. The same principle should apply to RPC and MQ traffic: they should be enabled after the SmartLifecycle or ContextRefreshedEvent points.
Best practice: delay opening inbound traffic until Spring has fully started.
What business characteristics suit the publish‑subscribe model?
Publishers do not care how events are processed.
Publishers do not care about the processing result.
Multiple subscribers can handle events synchronously or asynchronously.
Subscribers are independent and do not depend on each other.
The model decouples publishers and subscribers but is not suitable for strong‑consistency scenarios.
3. Strong‑consistency scenarios are not suitable for publish‑subscribe
In order‑creation scenarios, inventory deduction and order placement must be fully consistent. If inventory deduction fails while the order succeeds, data anomalies occur, which the Spring Event model cannot roll back automatically.
Event publishers cannot know which subscribers failed, making reliable rollback difficult.
4. Eventual‑consistency scenarios are ideal for the publish‑subscribe model
After an order is successfully placed, publishing an MQ message to release locks is a typical eventual‑consistency use case. The post‑processing should not affect the already‑successful order.
All subscribers for a successful‑order event should eventually succeed; failures can be retried until success.
Without Spring Event, developers would need to implement the observer pattern manually or add new Kafka consumer groups for each new business logic.
5. Using Spring Event requires additional reliability guarantees
Publish events with applicationContext.publishEvent(event) . If a subscriber throws an exception, the method propagates the exception, allowing the publisher to detect failure.
Three ways to handle subscriber failures:
Subscriber retries itself – e.g., using Spring Retry annotations.
Example with @Retryable :
@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 100L, multiplier = 2))
public void performSuccess(PerformEvent event) {
// business logic
}Remember to add the spring-retry dependency:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.4.RELEASE</version>
</dependency>When using Kafka, a failed consumer can return a failure to trigger Kafka’s own retry mechanism, or send the message to a dead‑letter queue.
6. Spring subscribers must be idempotent
Because retries re‑execute all subscribers, each subscriber must be idempotent to avoid data inconsistency.
Why have both MQ and Spring Event?
MQ is stronger and suited for inter‑service decoupling, while Spring Event is lightweight and ideal for intra‑application decoupling. They complement each other rather than replace one another.
Spring Event and MQ both follow the publish‑subscribe pattern; MQ is more powerful for cross‑service communication, whereas Spring Event is better for internal module decoupling.
Source: juejin.cn
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
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.