Spring关于Event的相关文档
准备工作
在spring容器初始化时会做两件事(参考AbstractApplicationContext#refresh方法):
1.初始化一个事件广播器
AbstractApplicationContext#initApplicationEventMulticaster
事件广播器对象主要是用来发布事件的,从上面的源码可以看出来,spring默认注册一个SimpleApplicationEventMulticaster类型的广播器对象,且bean的名字固定是applicationEventMulticaster,我们可以自定义一个来覆盖spring默认的配置,当然,名字必须是applicationEventMulticaster。
2.扫描事件监听器
事件监听器是用来监听广播出来的的事件的,Spring中有两种方式来定义一个事件监听器:
1.实现ApplicationListener接口
2.在一个bean上加@EventListener注解
相对应的,其扫描方式也分为了两个:
针对实现ApplicationListener接口的,是在Spring实例化所有bean之后,扫描得到所有实现了ApplicationListener接口的bean的名称,放到SimpleApplicationEventMulticaster中的一个Set集合中,参考AbstractApplicationContext#registerListeners:
针对加了加@EventListener注解的,spring是通过一个EventListenerMethodProcessor类来处理的,查看源码可以发现,其是实现了SmartInitializingSingleton接口,这个接口之前分析spring源码的时候也说过,是在bean初始化完成之后回调的,可以理解为和InitializingBean差不多的功能。
spring首先会将这个bean加到容器中,当其实例化出来之后就会回调SmartInitializingSingleton接口的afterSingletonsInstantiated方法,在这方法里面扫描出所有加了@EventListener注解的bean:
广播一个事件
初始化做完之后,我们该怎么广播一个事件呢?这个就要借助于SimpleApplicationEventMulticaster的multicastEvent方法了,这个方法会要求传入一个ApplicationEvent对象或者其子类对象,代表要广播出去的事件类型。大概的原理就是遍历之前容器初始化时扫描到的事件监听器,找到监听该事件的所有监听器,然后触发:
最终就调用到了该事件监听器的onApplicationEvent方法:
最后一个问题,如何去取这个事件广播器
针对这个问题,从上面的源码中可以看到,spring初始化时是将广播器对象放到容器中的,所以一般只要利用注解注入就行了。这里之所以要单独拎出来是因为spring还提供了一种特殊的方式,就是实现ApplicationEventPublisherAware接口。
注意这里的参数是一个ApplicationEventPublisher对象,划重点:
***Aware接口的用途很明确了,实现了该接口,spring自动为你注入事件广播器对象,其源码在ApplicationContextAwareProcessor这个后置处理器中(之前的spring源码中有讲过,属于spring第七次后置处理器执行逻辑):
有没有发现这里注入的是一个spring容器上下文对象,事实上确实如此,AnnotationConfigApplicationContext对象间接实现了ApplicationEventPublisher接口,也就实现了publishEvent方法,该方法就中能广播事件了。
为什么能广播?因为AnnotationConfigApplicationContext在spring容器初始化时就已经将SimpleApplicationEventMulticaster对象赋值到了其成员变量applicationEventMulticaster,参考上面的初始化事件广播器。