1. Spring Event 核心问题与最佳实践
作为一名经历过线上事故的Java开发者,我想分享一些关于Spring Event的实战经验。Spring Event作为Spring框架内置的事件发布-订阅机制,看似简单却暗藏玄机。我们团队曾因不当使用导致线上事故,经过复盘总结出6条关键经验,希望能帮助大家避开这些坑。
Spring Event的核心机制是:开发者定义事件对象,通过ApplicationContext发布事件,Spring会自动将事件广播给所有监听该事件的监听器。监听器可以通过实现ApplicationListener接口或使用@EventListener注解来注册。
1.1 优雅关闭服务是使用Spring Event的前提
线上曾出现一个诡异问题:服务关闭期间出现"Get Bean时找不到对应bean"的异常。堆栈信息显示"Do not request a bean from a BeanFactory in a destroy method implementation"——这是Spring的硬性限制:应用上下文关闭期间禁止获取Bean。
问题根源在于:
- 高流量服务在关闭期间仍有请求进入
- 这些请求触发了Spring Event的发布
- Spring尝试获取监听器Bean时失败
解决方案:
- 实现优雅关闭:先切断入口流量(HTTP、MQ、RPC)
- 确保所有请求处理完成后再关闭Spring上下文
- 推荐使用Spring Boot Actuator的优雅关闭端点
关键点:服务关闭顺序应该是:1. 停止接收新请求 2. 处理完存量请求 3. 关闭应用上下文
1.2 服务启动阶段的事件丢失问题
我们遇到过Kafka消费者在init-method阶段就开始消费消息,但此时@EventListener监听器尚未注册完成,导致事件丢失。
根本原因是Spring Bean的初始化顺序:
- Bean实例化
- 属性注入
- init-method执行
- 监听器注册
解决方案:
- 使用SmartLifecycle控制流量开启时机
- 或监听ContextRefreshedEvent事件
- 确保所有监听器注册完成后再开启流量
示例代码:
java复制@Component
pu
