Spring的Event事件通知/监听

一、为什么要使用事件通知/监听

现在有如下业务场景:
用户A订购了某件商品,按照业务流程,完成订购后,还需要发送成功订购的短信、邮件。一般我们会在用户订购的服务中,完成用户订购操作,然后调用发送短信的服务和发送邮件的服务,完成一整套订购流程。
这样的代码耦合性非常强,因为随着业务的扩展、变化,可能订购完成了还会增加新的事件,比如增加积分。按照传统的写法,我们就要在订购服务中再调用积分的服务。

那么,如何将这些高耦合的代码抽出去呢?
我们就要使用事件通知/监听机制,将发送短信/邮件、累计积分这些服务,作为监听者,而订购商品的操作,作为事件的发布者。很显然,这使用了行为模式中的观察者模式。

二、spring的事件监听示例

我们根据上述的业务场景,写一个简单的例子:

1、我们如果要使用spring的事件,首先需要定义一个事件,这里我们定义了一个用户订购事件。定义事件需要继承spring提供的ApplicationEvent,该类继承了JDK中的事件基类EventObject。因而自定义事件除了需要继承ApplicationEvent之外,还要传入事件源作为构造参数。
在这里插入图片描述

2、然后我们定义一个事件发布者,也就是用户订购服务。
ApplicationEventPublishAware是由Spring提供的,用于Service注入ApplicationEventPublisher事件发布器的接口,至于这个事件发布器到底是什么,我们在后续介绍。
使用这个接口,我们的Service就拥有发布事件的能力了.
这样用户订购后,不再显式的调用其他的业务Service,而是发布一个用户订购事件。
在这里插入图片描述
Spring4.2之后,ApplicationEventPublisher自动被注入到容器中,不再需要显式实现Aware接口。在这里插入图片描述

3、最后我们定义事件订阅者:短信服务
事件订阅者的服务同样需要托管于Spring容器。ApplicationListener接口是Spring提供的事件订阅者必须实现的接口,我们一般把Service关心的事件作为泛型传入.
事件处理:ApplicationEvent#getSource拿到事件的具体内容,这里是一个map。
在这里插入图片描述
注解式的事件订阅者:@EventListener注解完成了ApplicationListener接口的使命:
在这里插入图片描述
注:如果需要异步执行,则配置@EnableAsync模块注解开启异步支持,使用@Async注解对需要异步的监听器进行标注:
在这里插入图片描述
在这里插入图片描述
关于该注解的原理,其实就是将真正的方法包装成一个Callable任务,将这个任务提交到executor中执行。

4、运行看看结果:
在这里插入图片描述
在这里插入图片描述

三、源码解析

spring是如何实现这种通知和监听的呢?
回到之前的例子,我们在事件发布者:UserOrderServiceImpl中,调用了ApplicationEventPublisher的publishEvent(ApplicationEvent event)方法,来进行事件的发布:
在这里插入图片描述
我们就先进入publishEvent方法来看一下,该方法位于AbstractApplicationContext类中:
在这里插入图片描述
在这里插入图片描述

在这个方法中,首先判断传入的事件是不是一个ApplicationEvent对象,如果不是,则将其包装成PayloadApplicationEvent事件,并获取对应的事件类型。
最后通过applicationEventMulticaster(这里的applicationEventMulticaster是哪里来的后面会介绍),调用multicastEvent方法来广播出去,下面我们看一下multicastEvent方法:
在这里插入图片描述
可以看到,该方法获取SimpleApplicationEventMulticaster中的线程执行器,如果存在线程执行器则在新线程中异步执行,否则直接同步执行监听器中的方法invokeListener。在这里插入图片描述

在invokeListener方法中,如果存在ErrorHandler,则调用监听器方法,如果抛出异常则调用ErrorHandler来处理异常。否则直接调用监听器方法。
doInvokeListener就是执行监听器方法了:
在这里插入图片描述
之前说到,publishEvent方法有一个getApplicationEventMulticaster()方法来获取广播器ApplicationEventMulticaster,然后调用广播器的multicastEvent方法来广播出去。那么这个广播器是什么时候建立的呢?
applicationEventMulticaster在Spring的启动过程中被建立,在启动的核心方法refresh中,会建立applicationEventMulticaster:
在这里插入图片描述
这里的initApplicationEventMulticaster()用于在Spring容器中初始化事件广播器,用于事件的发布。
而registerListeners()用于把Spring容器内的事件监听器和BeanFactory中的事件监听器都添加进事件广播器中。

initApplicationEventMulticaster方法:
在这里插入图片描述
在该方法中,如果用户手动新建了一个名为applicationEventMulticaster类型为ApplicationEventMulticaster的bean,则将这个bean作为事件广播器,否则新建一个SimpleApplicationEventMulticaster作为默认的广播器。

registerListeners方法:
在这里插入图片描述
这个注册监听器方法,首先把提前存储好的监听器添加到监听器容器中,然后获取类型是ApplicationListener的beanName集合,但不会去实例化bean。如果存在earlyEventsToProcess,则提前处理这些事件。

四、思考

那么如果做一个事件中心,是不是可以运用这种模式呢?
假设现在有四个中心:日志中心、体温中心、告警中心、事件中心。日志中心和告警中心,需要监听体温超过38度的数据,于是就可以向事件中心发起请求。
事件中心接收到请求后,注册监听事件,监听体温中心的推送。
体温中心在体温超过38度时,发布事件给事件中心。
事件中心向注册过的中心发送广播。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值