
网络上比较推崇使用Spring Event 优雅的实现观察者模式。我在调研后也确实觉得这种方式能实现业务逻辑上的解耦但线上的一次事故让我意识到 Spring Event远远没有那么简单。前几天线上系统出现两条异常日志Get Bean时找不到对应的bean调用堆栈让我非常迷惑为什么Get Bean找不到对应的Bean呢? 堆栈中的信息 解释了原因。Do not request a bean from a BeanFactory in a destroy method implementation在应用上下文关闭时不得从上下文中Get Bean。恰好问题出现在服务关闭期间… 由于系统流量较高日订单几百万即便在低峰期单机的并发度也是比较高的所以服务在关闭期间有少量流量进来或未处理完。要明白问题原因和解决办法需要先简单了解 Spring Event如何使用总共分为三步。声明事件发布事件监听事件声明事件自定义事件需要继承Spring ApplicationEvent。我选择使用泛型支持子类可以灵活关联事件的内容。public class BaseEventT extends ApplicationEvent { private final T data; public BaseEvent(T source) { super(source); this.data source; } public T getData() { return data; } }发布事件使用Spring上下文 ApplicationContext发布事件applicationContext.publishEvent(new BaseEvent(param));Idea为Spring提供了跳转工具点击绿色按钮位置就可以 跳转到事件的监听器列表。监听事件监听器只需要 在方法上声明为 EventListener注解Spring就会自动找到对应的监听器。Spring会根据方法入参的事件类型和 发布的事件类型 自动匹配。EventListenerpublicvoidhandleEvent(BaseEventPerformParamevent){//消费事件}我遇到的线上问题恰恰出现在发布事件后Spring匹配Listener时Spring需要从上下文中Get Bean每发布一次事件需要Get Bean一次。正常情况下没事在服务关闭期间如果恰好发布了一个事件就凉了。在调研Spring Evnet期间我重点考虑了使用方式使用的优缺点但确实没有想到Spring会有这个缺陷。如何避免这个问题呢弃用SpringEvent。允许Spring Event 出现异常但上层调用捕获异常上报MQ重试。彻底服务优雅关闭。Rpc、Http、MQ入口在进程关闭前先禁用流量。结合三个方案的改动成本我选择忍痛弃用Spring Event。这件事让我明白了全面调研真的很困难某些框架确实很好用但没准在哪个点上就有坑。有时候保守不是一件坏事至少能保证线上环境能稳定运行啊。最后分享下五阳的 AI 工具同时提问豆包 DeepSeek GPT Gemini等九大 AI 平台还支持查询必应 百度 谷歌三大搜索引擎检索资料效率提升十倍不止每次提问参考资料用不完……领取链接领取链接适用于360浏览器领取链接适用于Chrome浏览器领取链接适用于Edge浏览器