每天进步一点点,大家好,我是大龄码农。
今天我们聊聊事件的源码。
大家是否还记得refresh()方法,一个非常重要的方法,在AbstractApplicationContext类中。

说明:今天要着重介绍的,就是被框出来的这三个方法
一、initApplicationEventMulticaster()


说明:这个方法比较简单,查找是否有名为“applicationEventMulticaster”的bean,如果有就使用自定义的,如果没有就使用默认的SimpleApplicationEventMulticaster类,并手工注册到Spring容器中

说明:这是继承关系图,对于类中的属性和方法,在后面分析时再说
二、registerListeners()


说明:第一段代码是获取容器中所有的监听器对象并添加到事件广播器中,第二段代码是获取所有类型为ApplicationListener的bean名单并添加到事件广播器中,第三段代码是获取早期事件并发布
在讲finishRefresh()方法之前,我们再说一下在finishBeanFactoryInitialization()这个非常重要的方法中发生了什么?其实就是后置处理器又搞了哪些事情。
1、ApplicationListenerDetector

说明:这是专门用于处理ApplicationListener的,实现了BeanPostProcessor接口

说明:将ApplicationListener添加到容器中

说明:广播器将listener添加到其内部类DefaultListenerRetriever中
2、EventListenerMethodProcessor

说明:这是专门用于处理@EventListener注解的。
实现BeanFactoryPostProcessor接口的postProcessBeanFactory()方法

说明1:EventListenerFactory有两个实现类,一个是DefaultEventListenerFactory,对应处理@EventListener注解,另一个是TransactionalEventListenerFactory,对应处理@TransactionalEventListener注解。
说明2:由于@TransactionalEventListener注解更特殊,所以通过排序将其放在第一个去匹配处理对应的方法
实现SmartInitializingSingleton接口的afterSingletonsInstantiated()方法
其中,调用了processBean()方法

说明:筛选出@EventListener注解的方法

说明1:如果方法不为空时执行这部分逻辑,对于红框部分的逻辑,如果factory的类型是DefaultEventListenerFactory时,会创建ApplicationListenerMethodAdapter对象,如果factory的类型是TransactionalEventListenerFactory时,会创建TransactionalApplicationListenerMethodAdapter对象。
说明2:将注解对应的监听器对象存入到容器中
三、finishRefresh()

说明:这里发布了一个ContextRefreshedEvent事件



说明:这里主要就是初始化事件并广播

说明:查到符合条件的监听器并调用对应的onApplicationEvent()方法。这里主要看下getApplicationListeners()方法中的retrieveApplicationListeners()方法

说明1:初始化监听器(类型为ApplicationListener的bean以及被@EventListener注解转化为XXXMethodAdapter对象的bean)和监听器的bean名单(类型为ApplicationListener的bean)
说明2:将匹配对应事件类型的监听器存入到待返回的监听器中


说明1:针对监听器的bean名单中的bean再做一次判断,检查其是否支持对应的事件,如果不支持就从待返回的监听器中移出。
说明2:这部分代码在一定程度上,会与已注册的监听器有部分重叠。
源码分析到这里,我们回头看下Spring事件中的问题
问题:为什么使用ApplicationContext能自动监听到事件,而使用自定义的事件发布器就不能自动监听到事件呢?
回答:答案很简单,就是缺少了multicastEvent()这个步骤,因为在这个方法中,会获取所有符合条件的监听器,并调用其处理事件的方法。所以通过手动调用SimpleApplicationEventMulticaster类的multicastEvent()方法,问题得到解决。
最后,再说下线程池,刚才在源码分析中大家也看到了Executor类,默认是null,因为@EventListener注解默认是在发布事件的线程上同步执行监听器方法,也就是串行化执行。如果想要并发执行,就要指定线程池。这里有两种实现方式:
自定义ApplicationEventMulticaster
从源码得知,SimpleApplicationEventMulticaster这个类是支持监听器异步调用的,但是每次通过context获取bean后再设置taskExecutor属性,总觉得怪怪的。不如索性自定义ApplicationEventMulticaster,并实现这部分逻辑。
定义线程池

说明:修改线程前缀,这样能看出差异
自定义ApplicationEventMulticaster

说明:注意bean的名称只能是applicationEventMulticaster。
我们在原有代码的基础之上,增加关于线程的打印信息,测试结果如下

说明:main线程串行执行
增加自定义ApplicationEventMulticaster后,测试结果如下

说明:指定线程池,监听器并发执行
注意:这里所有的监听器都变成了异步执行
使用@Async注解
1、使用@EnableAsync注解标识支持异步
一般在启动类上标注
2、使用@Async注解标明要使用的线程池
这里在NewArticleListenerB类的onListenEvent()方法上增加@Async注解

测试结果

说明:@Async注解可以让指定的监听器异步执行,其他的监听器依然串行执行
夜雨聆风