Spring Event事件订阅框架,被网上一些人快吹上天了,然而我们在新项目中引入后发现,这个框架缺陷很多,玩玩可以,千万不要再公司项目中使用。还不如自己手写一个监听者设计模式,那样更稳定、可靠。
之前我已经被Spring Event(事件发布订阅组件)坑过一次。那次是在服务关闭期间,有请求未处理完成,当调用Spring Event时,出现异常。
根源是:Spring关闭期间,不得调用GetBean,也就是无法使用Spring Event 。详情点击这里查看
然而新项目大量使用了Spring Event,在另一个Task服务还未来得及移除Spring Event的情况下,出现了类似的问题。
当领导听说新引入的Spring Event再次出现问题时,非常愤怒,因为一个月内出现了两次故障。在复盘会议上,差点爆粗口。
“五哥,你看一眼钉钉给你发的监控截图,线上好像有丢消息?” 旁边同事急匆匆的跟我说。
“线上有问题?强哥在上线,我让他先暂停下~”,于是我赶紧通知强哥,先暂停发布。优先排查线上问题~
怎么会有问题呢?我有点意外,正好我和强哥各有代码上线,我只改动很小一段代码。我对这次代码变更很自信,坚信不会有问题,所以我并没有慌乱和紧张。搁之前,我的小心脏早就怦怦跳了!
出现问题的业务逻辑是 消费A 消息,经过业务处理后,再发送B消息。
从线上监控和日志分析,Task服务收到了 A 消息,然后处理失败了。诡异之处是没有任何异常日志和异常打点,仿佛凭空消失了。
分析代码分支后,我和同事十分确信,任何异常退出的代码分支都有打印异常日志和上报异常监控打点,出现异常不可能不留一丝痕迹。
正当陷入困境之时,我们发现蹊跷之处。“丢消息”的时间只有 3秒钟,之后便恢复正常。问题出在启动阶段,消息A进入Task服务,服务还未完全发布完成时,导致不可预测的情况发生。
当分析Spring 源代码以后,我们发现原因出在 Spring Event……
在详细说明问题根源前,我简单介绍一下 SpringEvent使用,熟悉它的读者,可以自行跳过。
自定义事件需要继承Spring ApplicationEvent。我选择使用泛型,支持子类可以灵活关联事件的内容。