当前位置: 首页 > news >正文

Spring的事件监听机制

这里写自定义目录标题

  • 1. 概述(重点)
  • 2. ApplicationEventMulticaster
    • 2.1 SimpleApplicationEventMulticaster
    • 2.2 AbstractApplicationEventMulticaster
  • 3. ApplicationListener
    • 3.1 注册监听器
    • 3.2 自定义
  • 4. SpringApplicationRunListeners

1. 概述(重点)

事件监听机制是观察者模式的一种,Spring的事件监听机制有几个重要的顶层接口,分别是:

  1. ApplicationEventMulticaster 主要看 AbstractApplicationEventMulticaster
  2. ApplicationListener
  3. ApplicationEvent

它们三哥们的关系可以用下面的图来概括

在这里插入图片描述
AbstractApplicationEventMulticaster维护了 源类型和事件类型 作为KEY 跟 监听器的关系,在下面 2.1 SimpleApplicationEventMulticaster有代码的实现解读。

2. ApplicationEventMulticaster

AbstractApplicationEventMulticaster
«Interface»
ApplicationEventMulticaster
«Interface»
Aware
«Interface»
BeanClassLoaderAware
«Interface»
BeanFactoryAware
SimpleApplicationEventMulticaster

目前就只有一个实现类SimpleApplicationEventMulticaster和一个抽象类AbstractApplicationEventMulticaster

2.1 SimpleApplicationEventMulticaster

发布和广播事件,主要注意一下getApplicationListeners方法就行了,会根据事件类型源类型找监听器。

@Override
public void multicastEvent(ApplicationEvent event) {multicastEvent(event, resolveDefaultEventType(event));
}@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));Executor executor = getTaskExecutor();for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {if (executor != null) {executor.execute(() -> invokeListener(listener, event));}else {invokeListener(listener, event);}}
}

2.2 AbstractApplicationEventMulticaster

getApplicationListeners方法就是根据Class<?>、ResolvableType两个对象作为一个缓存key,这个key与一堆监听器`ApplicationListener`做映射,也就是说通过Class<?>、ResolvableType两个对象可以找到监听器,在用法上可以从SimpleApplicationEventMuticastermulticastEvent 方法去看。

看看getApplicationListeners方法的代码实现

protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {Object source = event.getSource();Class<?> sourceType = (source != null ? source.getClass() : null);ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);CachedListenerRetriever newRetriever = null;// 这个cacheKey就是ApplicationEvent,ResolvableType两个对象。// 根据cacheKey找监听器,找不到就把cacheKey作为key,创建一个什么都么有的CachedListenerRetriever对象作为值缓存到retrieverCache中。// 这里有一些细节我没搞明白,putIfAbsent总是返回null。CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);if (existingRetriever == null) {if (this.beanClassLoader == null ||(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {newRetriever = new CachedListenerRetriever();existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);if (existingRetriever != null) {newRetriever = null;  // no need to populate it in retrieveApplicationListeners}}}if (existingRetriever != null) {Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();if (result != null) {return result;}}// 假设上面cacheKey对应的值没有监听器,那这个方面就找 给定事件类型和源类型 的监听器。return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}// 从默认的 defaultRetriever 和 我们注入的bean 中找监听器。
private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {List<ApplicationListener<?>> allListeners = new ArrayList<>();Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);Set<ApplicationListener<?>> listeners;Set<String> listenerBeans;synchronized (this.defaultRetriever) {listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);}// 从defaultRetriever中找监听器// 这里的supportsEvent有点看不懂,不过只要理解通过事件类型和源类型判断监听器是否符合 事件要求就得了。for (ApplicationListener<?> listener : listeners) {if (supportsEvent(listener, eventType, sourceType)) {if (retriever != null) {filteredListeners.add(listener);}allListeners.add(listener);}}// 根据bean名字去找监听器if (!listenerBeans.isEmpty()) {ConfigurableBeanFactory beanFactory = getBeanFactory();for (String listenerBeanName : listenerBeans) {try {if (supportsEvent(beanFactory, listenerBeanName, eventType)) {ApplicationListener<?> listener =beanFactory.getBean(listenerBeanName, ApplicationListener.class);if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {if (retriever != null) {if (beanFactory.isSingleton(listenerBeanName)) {filteredListeners.add(listener);}else {filteredListenerBeans.add(listenerBeanName);}}allListeners.add(listener);}}else {Object listener = beanFactory.getSingleton(listenerBeanName);if (retriever != null) {filteredListeners.remove(listener);}allListeners.remove(listener);}}catch (NoSuchBeanDefinitionException ex) {}}}// 把找到的监听器都放到CachedListenerRetriever中。AnnotationAwareOrderComparator.sort(allListeners);if (retriever != null) {if (filteredListenerBeans.isEmpty()) {retriever.applicationListeners = new LinkedHashSet<>(allListeners);retriever.applicationListenerBeans = filteredListenerBeans;}else {retriever.applicationListeners = filteredListeners;retriever.applicationListenerBeans = filteredListenerBeans;}}return allListeners;
}

3. ApplicationListener

主要是了解如何注册和自定义监听器就行了

3.1 注册监听器

通过META-INF/spring.factories注册监听器。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath();this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 这里就是注册ApplicationListener的代码了,通过META-INF/spring.factories注册。setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();
}

3.2 自定义

public class MyApplicationPreparedListener implements ApplicationListener<ApplicationPreparedEvent> {@Overridepublic void onApplicationEvent(ApplicationPreparedEvent event) {System.out.println("开始填充上下文。。。。");}
}

MATE-INF/spring.factories

org.springframework.context.ApplicationListener=sample.config.MyApplicationPreparedListener

4. SpringApplicationRunListeners

SpringApplicationRunListeners管理了多个EventPublishingRunListener,EventPublishingRunListener里面包含了事件监听器模型#1.概述(重点)中描述的部分。

class SpringApplicationRunListeners {private final Log log;private final List<SpringApplicationRunListener> listeners;private final ApplicationStartup applicationStartup;...
}public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {private final SpringApplication application;private final String[] args;private final SimpleApplicationEventMulticaster initialMulticaster;...
}

EventPublishingRunListener中定义了Spring整个启动过程中会触发的事件,下面对触发位置进行大概的描述,更具体的内容还有待研究。

  • starting
    在SpringApplication#run,事件ApplicationStartingEvent
  • environmentPrepared
    在SpringApplication#prepareEnvironment,事件ApplicationEnvironmentPreparedEvent
  • contextPrepared
    在SpringApplication#prepareContext,事件ApplicationContextInitializedEvent
  • contextLoaded
    在SpringApplication#prepareContext,事件ApplicationPreparedEvent
  • started
    在SpringApplication#run,事件ApplicationStartedEvent
  • ready
    在SpringApplication#run,事件ApplicationReadyEvent
  • failed
    在SpringApplication#handleRunFailure,事件ApplicationFailedEvent

我们也可以利用上面的事件,自己创建一个监听器,然后放到spring.factories,比如现在注册一个ApplicationPreparedEvent的监听器。

public class MyApplicationPreparedListener implements ApplicationListener<ApplicationPreparedEvent> {@Overridepublic void onApplicationEvent(ApplicationPreparedEvent event) {System.out.println("开始填充上下文。。。。");}
}

MATE-INF/spring.factories

org.springframework.context.ApplicationListener=sample.config.MyApplicationPreparedListener
http://www.lryc.cn/news/291919.html

相关文章:

  • Zookeeper分布式命名服务实战
  • DEV-C++ ege.h库 绘图教程(六)
  • MySQL原理(一)架构组成之物理文件组成
  • 代码随想录算法训练营第三十七天 | 738.单调递增的数字、 968.监控二叉树
  • 【Django-ninja】django-ninja的hello world
  • ArrayList集合初始化长度是多少,初始化的时候分配内存空间吗
  • C语言数组:从入门到进阶
  • 9.回文数
  • 一分钟在SpringBoot项目中使用EMQ
  • SOME/IP 协议介绍(七)传输 CAN 和 FlexRay 帧
  • 与数组相关经典面试题
  • 数据结构与算法面试系列-02
  • CMake 完整入门教程(五)
  • pgsql中with子句和直接查询差别
  • Day 31 | 贪心算法 理论基础 、455.分发饼干 、 376. 摆动序列 、 53. 最大子序和
  • vue3使用is动态切换组件报错Vue received a Component which was made a reactive object.
  • React16源码: React中LegacyContext的源码实现
  • Gin 框架之jwt 介绍与基本使用
  • 从[redis:LinkedList]中学习链表
  • Prometheus+grafana配置监控系统
  • Linux之安装配置CentOS 7
  • 神经网络与深度学习Pytorch版 Softmax回归 笔记
  • git学习及简单maven打包
  • 如何用MapTalks IDE来发布网站?
  • 我用selenium开发了一个自动创建任务,解放重复性工作
  • 安卓11修改HDMI自适应分辨率
  • Linux实验记录:使用Apache的虚拟主机功能
  • 分布式空间索引了解与扩展
  • Set和Map的应用场景
  • 小白级教程,10秒开服《幻兽帕鲁》