所有分类
  • 所有分类
  • 未分类

Spring Event–踩坑(注意事项)

简介

本文介绍Spring的事件的使用注意事项。

Spring Event框架实现了基于事件的发布订阅机制。开发者可以自定义事件,发布事件,Spring 会将该事件广播给监听该事件的监听者。监听者可以实现Spring 的监听者接口 ApplicationListener注册自己,也可以使用 EventListener注解注册自己。

但是,Spring Event不要随便用!有很多注意事项。

1.必须实现优雅关闭服务

Spring 广播消息时会在 ApplicationContext 中查找所有的监听者:通过 getBean 获取 bean 实例。但Spring 有个限制:ApplicationContext 关闭期间,不要getBean,否则会报错。

前几天,线上系统出现两条异常日志:Get Bean时找不到对应的bean:

堆栈中的信息为:Do not request a bean from a BeanFactory in a destroy method implementation

原因分析

这个问题出现在服务关闭期间,在应用上下文关闭时,此Bean已被销毁,从上下文中Get Bean,结果没有获取到Bean,导致报错。

由于系统流量较高,日订单几百万,即便在低峰期单机的并发度也是比较高的,所以服务在关闭期间有少量流量进来或未处理完。这个场景下,使用 Spring Event 发布事件,一定会出现异常,导致处理失败!

大家一定要切记!使用 SpringEvent 之前,一定要先治理服务,确保服务关闭时,先切断入口流量(Http、MQ、RPC),然后再关闭服务,关闭 Spring 上下文!

2. 服务启动时,Spring 事件可能丢失

Kafka conumser 在 init-method 阶段开始消费,然而 Spring EventListener 被注册进 Spring 的时间点晚后于 init-method 时间点,所以 Kafka Consumer 中使用 Spring Event 发布事件时,没有找到监听者,出现消息处理丢失的情况。

从下图中可以看到 init-method 时间点 早于 EventListener 被注册的时间点(SmartlnitializingSingleton#afterSingletonlnstantiated)。

SpringBoot 会在Spring完全启动完成后,才开启Http流量。Rpc和 MQ流量 也应该如此,所以建议大家 在 ApplicationListener、ApplicationRunner等位置 注册服务,开启流量。

最佳实践是:改造系统开启入口流量(Http、MQ、RPC)的时机,确保在Spring 启动完成后开启入口流量。 ​

0

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录