Spring关于Event的相关文档

准备工作

在spring容器初始化时会做两件事(参考AbstractApplicationContext#refresh方法):

1.初始化一个事件广播器

AbstractApplicationContext#initApplicationEventMulticaster

java 内部广播 spring 广播_spring

事件广播器对象主要是用来发布事件的,从上面的源码可以看出来,spring默认注册一个SimpleApplicationEventMulticaster类型的广播器对象,且bean的名字固定是applicationEventMulticaster,我们可以自定义一个来覆盖spring默认的配置,当然,名字必须是applicationEventMulticaster。

2.扫描事件监听器

事件监听器是用来监听广播出来的的事件的,Spring中有两种方式来定义一个事件监听器:

1.实现ApplicationListener接口

2.在一个bean上加@EventListener注解

相对应的,其扫描方式也分为了两个:

针对实现ApplicationListener接口的,是在Spring实例化所有bean之后,扫描得到所有实现了ApplicationListener接口的bean的名称,放到SimpleApplicationEventMulticaster中的一个Set集合中,参考AbstractApplicationContext#registerListeners:

java 内部广播 spring 广播_java 内部广播_02

针对加了加@EventListener注解的,spring是通过一个EventListenerMethodProcessor类来处理的,查看源码可以发现,其是实现了SmartInitializingSingleton接口,这个接口之前分析spring源码的时候也说过,是在bean初始化完成之后回调的,可以理解为和InitializingBean差不多的功能。

spring首先会将这个bean加到容器中,当其实例化出来之后就会回调SmartInitializingSingleton接口的afterSingletonsInstantiated方法,在这方法里面扫描出所有加了@EventListener注解的bean:

java 内部广播 spring 广播_事件监听器_03

 

广播一个事件

初始化做完之后,我们该怎么广播一个事件呢?这个就要借助于SimpleApplicationEventMulticaster的multicastEvent方法了,这个方法会要求传入一个ApplicationEvent对象或者其子类对象,代表要广播出去的事件类型。大概的原理就是遍历之前容器初始化时扫描到的事件监听器,找到监听该事件的所有监听器,然后触发:

java 内部广播 spring 广播_spring_04

最终就调用到了该事件监听器的onApplicationEvent方法:

java 内部广播 spring 广播_spring_05

 

最后一个问题,如何去取这个事件广播器

针对这个问题,从上面的源码中可以看到,spring初始化时是将广播器对象放到容器中的,所以一般只要利用注解注入就行了。这里之所以要单独拎出来是因为spring还提供了一种特殊的方式,就是实现ApplicationEventPublisherAware接口。

注意这里的参数是一个ApplicationEventPublisher对象,划重点:

java 内部广播 spring 广播_java 内部广播_06

***Aware接口的用途很明确了,实现了该接口,spring自动为你注入事件广播器对象,其源码在ApplicationContextAwareProcessor这个后置处理器中(之前的spring源码中有讲过,属于spring第七次后置处理器执行逻辑):

java 内部广播 spring 广播_事件监听器_07

有没有发现这里注入的是一个spring容器上下文对象,事实上确实如此,AnnotationConfigApplicationContext对象间接实现了ApplicationEventPublisher接口,也就实现了publishEvent方法,该方法就中能广播事件了。

为什么能广播?因为AnnotationConfigApplicationContext在spring容器初始化时就已经将SimpleApplicationEventMulticaster对象赋值到了其成员变量applicationEventMulticaster,参考上面的初始化事件广播器。