Why Graceful Shutdown Matters Before Using Spring Event (and How to Avoid Common Pitfalls)
This article explains why services must be gracefully shut down before leveraging Spring Event, how startup timing can cause event loss, which consistency scenarios suit or reject publish‑subscribe, and practical reliability techniques such as retries, idempotence, and fault reporting.
1. Why graceful shutdown must be implemented before using Spring Event?
When Spring broadcasts an event it looks up all listeners in the ApplicationContext. During the context shutdown phase, calling getBean is prohibited and throws an error (e.g., "Do not request a bean from a BeanFactory in a destroy method implementation"). In high‑traffic systems, some requests may still arrive during shutdown, causing Spring Event to fail and raise exceptions. Therefore, before shutting down the Spring context you must first cut off inbound traffic (HTTP, MQ, RPC) to ensure no new work is submitted.
2. Why events can be lost during the service startup phase?
In the reported case a Kafka consumer started in the init-method phase, but the @EventListener beans were registered later, also in init-method. Because the listener registration lagged behind the consumer start, events published by the consumer found no listeners and were lost. The fix is to open inbound traffic only after Spring has fully started, for example by using SmartLifecycle or listening to ContextRefreshedEvent to register services.
3. Strong‑consistency scenarios are unsuitable for publish‑subscribe
In order‑placement workflows, inventory deduction and order confirmation must succeed or fail together. If a listener (e.g., inventory service) fails, Spring Event cannot roll back the whole transaction because each subscriber runs independently and exceptions are not propagated to the publisher. Implementing a compensating transaction across multiple listeners would be complex and error‑prone.
4. Eventual‑consistency scenarios fit publish‑subscribe
When the primary business action (e.g., order creation) has already succeeded, subsequent tasks such as releasing locks, sending MQ messages, or notifying downstream systems can be handled asynchronously via Spring Event. These follow‑up actions only need to succeed eventually; failures can be retried without affecting the original transaction. Example code uses @EventListener to handle events like order fulfillment, refund completion, or order expiration.
5. Ensure reliability when using Spring Event
Because Spring Event does not guarantee delivery or rollback, you must add reliability mechanisms:
Subscriber‑side retry : Use Spring Retry (e.g., @Retryable) so a failing listener automatically retries up to a configured number of attempts.
Kafka consumer‑group retry : If the event originates from a Kafka consumer, let Kafka handle retries by returning a consumption failure.
Report failures to a fault‑management platform : After exceeding retry limits, publish a fault message to a dedicated MQ that a monitoring system consumes, alerts developers, and provides a manual retry button.
@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 100L, multiplier = 2))
public void performSuccess(PerformEvent event) {
// business logic
} <dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.4.RELEASE</version>
</dependency>6. Subscribers must be idempotent
When retries occur, all listeners are invoked again, so each listener's logic must be idempotent to avoid duplicate side effects and data inconsistency.
7. Why use Spring Event even when MQ exists?
Message queues excel at decoupling separate services and handling cross‑service communication, while Spring Event is lightweight and ideal for intra‑application communication. They are complementary: use MQ for inter‑service events and Spring Event for internal, fine‑grained decoupling.
Source: https://juejin.cn/post/7281159113882468371
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.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
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.
