Key Considerations and Best Practices for Using Spring Event in Production
This article shares practical lessons from real‑world production incidents, explaining why graceful shutdown, proper listener registration timing, consistency requirements, retry mechanisms, idempotency, and traffic control are essential when using Spring Event in Java backend systems.
1. Why must a business system gracefully shut down before using Spring Event?
When Spring broadcasts an event it looks for listeners in the ApplicationContext . During the shutdown phase the context cannot retrieve beans, and attempting to do so throws an error such as "Do not request a bean from a BeanFactory in a destroy method implementation". In our production environment, high traffic caused a few requests to arrive while the service was shutting down, leading to missing beans and failed event publishing. The remedy is to cut off all entry traffic (HTTP, MQ, RPC) before closing the Spring context.
2. Why are events lost during the service startup phase?
In our case the Kafka consumer started in the init-method before the @EventListener beans were registered, so events published by the consumer could not find any listeners. The registration of listeners occurs later, after the init-method completes. The solution is to register services that open traffic only after the Spring context is fully refreshed, e.g., in a SmartLifecycle implementation or by listening to ContextRefreshedEvent .
What business characteristics suit the publish‑subscribe model?
Publishers do not need to know how events are processed.
Publishers do not care about the processing results.
Multiple subscribers can exist, supporting asynchronous or synchronous handling.
Subscribers are independent and do not depend on each other.
The model decouples producers and consumers but is not appropriate for strong‑consistency scenarios where a rollback is required.
3. Strong‑consistency scenarios are not suitable for publish‑subscribe
In order‑creation workflows, inventory deduction and order confirmation must be atomic. If a subscriber fails (e.g., inventory deduction fails) the whole transaction must roll back, which Spring Event cannot guarantee because it does not propagate subscriber failures back to the publisher.
4. Eventual‑consistency scenarios are ideal for Spring Event
After an order is successfully placed, downstream tasks such as sending MQ messages, releasing locks, or notifying settlement systems can be handled by Spring Event. These tasks only need to succeed eventually; retries are acceptable, and no immediate rollback of the main transaction is required.
5. Adding reliability guarantees to Spring Event
To ensure reliability, publish events with applicationContext.publishEvent(event) and handle exceptions. Three common approaches are:
Subscriber‑side retry : Use Spring Retry (e.g., @Retryable ) so that a failing subscriber method is automatically retried up to a configurable number of attempts.
Kafka consumer group retry : When using Kafka, let the consumer return a failure so Kafka retries the message, or route failed messages to a dead‑letter queue for later processing.
Report failures to a fault‑management platform : After exceeding retry limits, publish a fault event to an MQ that a monitoring system consumes, allowing operators to manually trigger a retry via RPC.
Example of a retryable method:
@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>6. Subscribers must be idempotent
Because retries will invoke all subscribers again, each subscriber's logic must be idempotent to avoid data inconsistencies.
Why use Spring Event when a message queue exists?
MQs are powerful for inter‑service communication and strong decoupling, while Spring Event is lightweight and ideal for intra‑application communication. They complement each other: use MQ for cross‑service events and Spring Event for internal, fine‑grained decoupling.
Conclusion
The author has published three technical columns on Spring Cloud, Spring Boot, and MyBatis. If this article helped you, please like, share, and follow the "Code Monkey Technical Column" public account for more resources and community discussions.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.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.