ApplicationListener实现原理
创始人
2024-05-30 08:52:54
0

自定义一个实现ApplicationListener接口的类:

@Component
public class MyApplicationListener implements ApplicationListener {@Overridepublic void onApplicationEvent(MyApplicationEvent event) {System.out.println("我是测试监听器的类方法:"+event.getSource());}
}

这里使用了@Component注解,此注解下节分析;

然后再自定义一个触发事件:

public class MyApplicationEvent extends ApplicationEvent {public MyApplicationEvent(Object source) {super(source);}
}

要达到的效果就是,当请求发布的事件是MyApplicationEvent事件的时候,就需要调用自定义的监听器;

执行结果:

 可以看到执行的结果就是想要的结果。那么代码是如何实现这一点的呢?

这里只看关键代码,首先要找到AbstractApplicationContext#refresh的方法,其中最后第二步实例化方法是finishBeanFactoryInitialization(beanFactory)方法,它是通过getBean(beanName)来实例化剩余的单利的;

在此过程中,会调用如下方法:

	@Overridepublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;}

看方法名称可知,其实初始化后应用bean的后置处理器的方法;

即调用了ApplicationListenerDetectorBeanPostProcessor的后置处理器,它实现了MergedBeanDefinitionPostProcessor接口,

注(在此之前已经执行):

所以在这之前,它会在doCreateBean的实例化之后调用其后置处理器的postProcessMergedBeanDefinition()方法,此处是将自定义的监听器添加到singletonNames中。

然后接着上面继续,它后置方法postProcessAfterInitialization()

	@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {if (bean instanceof ApplicationListener) {// potentially not detected as a listener by getBeanNamesForType retrievalBoolean flag = this.singletonNames.get(beanName);if (Boolean.TRUE.equals(flag)) {// singleton bean (top-level or inner): register on the flythis.applicationContext.addApplicationListener((ApplicationListener) bean);}else if (Boolean.FALSE.equals(flag)) {if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {// inner bean with other scope - can't reliably process eventslogger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +"but is not reachable for event multicasting by its containing ApplicationContext " +"because it does not have singleton scope. Only top-level listener beans are allowed " +"to be of non-singleton scope.");}this.singletonNames.remove(beanName);}}return bean;}

此时,先判断了一下对象是否是ApplicationListener类型,如果是,则添加到this.defaultRetriever.applicationListeners变量中,取值的时候,则会根据具体的类型进行判断

		for (ApplicationListener listener : listeners) {if (supportsEvent(listener, eventType, sourceType)) {if (retriever != null) {filteredListeners.add(listener);}allListeners.add(listener);}}

此时,就会将根据事件类型,添加相应的监听器,然后调用对应的onApplicationEvent方法。

当然,此处也可以使用spi的形式注入或者@Bean的形式都可以;

监听器可以实现线程上下文的的热更新等功能。

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...