今天我们重点聊聊使用 Spring Event 最为关键的几个问题。这是我司线上生产环境实际踩坑后,总结的极为宝贵的经验!
Spring Event框架实现了基于事件的发布订阅机制。开发者可以自定义事件,在某些业务场景发布事件,Spring 会将该事件广播给监听该事件的监听者。监听者可以实现Spring 的监听者接口 ApplicationListener注册自己,也可以使用 EventListener注解注册自己。
这是Spring Event 的简短介绍,网上有大量的入门级教程,我在此不过多赘述,进入正文!
1. 为什么说:业务系统一定要先实现优雅关闭服务,才能使用 Spring Event?
Spring 广播消息时,Spring会在 ApplicationContext 中查找所有的监听者,即需要 getBean 获取 bean 实例。然而 Spring 有个限制————ApplicationContext 关闭期间,不得GetBean 否则会报错。.
这个知识点得来不易。它是我们公司在线上环境发生故障后,最终定位的原因,大家一定要重视!
前几天,线上系统出现两条异常日志Get Bean时找不到对应的bean,调用堆栈让我非常迷惑,为什么Get Bean找不到对应的Bean呢? 如下图所示
堆栈中的信息 解释了原因。Do not request a bean from a BeanFactory in a destroy method implementation
在应用上下文关闭时,不得从上下文中Get Bean。恰好,这个问题出现在服务关闭期间…
由于系统流量较高,日订单几百万,即便在低峰期单机的并发度也是比较高的,所以服务在关闭期间有少量流量进来或未处理完。这个场景下,使用 Spring Event 发布事件,Spring 无法正常广播事件,一定会出现异常,导致处理失败!
大家一定要切记!使用 SpringEvent 之前,一定要先治理服务,确保服务关闭时,先切断入口流量(Http、MQ、RPC),然后再关闭服务,关闭 Spring 上下文!
详细的分析请参考:
https://juejin.cn/post/7281159113882468371
2. 为什么服务启动阶段,Spring Event 事件丢失了?
我们公司遇到的情况是, Kafka conumser 在 init-method 阶段开始消费,然而 Spring EventListener 被注册进 Spring 的时间点滞后于 init-method 时间点,所以 Kafka Consumer 中使用 Sp