监听器模式,大家应该并不陌生,主要的组成要素包括了事件、监听器以及广播器;当事件发生时,广播器负责将事件传递给所有已知的监听器,而监听器会对自己感兴趣的事件进行处理
我们来以应用启动事件:ApplicationStartingEvent为例来进行说明:
以启动类的SpringApplication.run方法为入口,跟进SpringApplication的两个同名方法后,我们会看到主要的run方法,方法比较长,在这里只贴出与监听器密切相关的关键的部分:
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
我们跟进这个starting方法,方法的内容如下:
void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
这里的listeners已经在getRunListeners方法中完成了加载,加载原理类似于系统初始化器,关于系统初始化器的加载可以参考SpringBoot深入浅出分析初始化器
starting方法逻辑很简单,就是调用SpringApplicationRunListener的starting方法。下面继续分析这个starting方法:
我们进入了EventPublishingRunListener类(SpringApplicationRunListener 的实现类)的starting方法:
@Override
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
这里就使用了广播器,来广播新的ApplicationStartingEvent事件。
我们跟进这个multicastEvent方法:
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
继续看同名的方法multicastEvent:
@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);
}
}
}
这里的ResolvableType 是对event做了包装,我们不去关注;由于我们没有创建线程池,所以executor是空的。我们重点关注两个部分:
1、getApplicationListeners --> 获取所有关注此事件的监听器(※);
2、invokeListener --> 激活监听器;
getApplicationListeners (AbstractApplicationEventMulticaster类中)方法,代码如下:
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);
// Quick check for existing entry on ConcurrentHashMap...
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// Fully synchronized building and caching of a ListenerRetriever
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(eventType, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// No ListenerRetriever caching -> no synchronization necessary
return retrieveApplicationListeners(eventType, sourceType, null);
}
}
入参中的event就是ApplicationStartingEvent,sourceType是org.springframework.boot.SpringApplication类。ListenerRetriever类型本人将其视作是一个保存监听器的容器。
可以看出,程序首先在缓存里面寻找ListenerRetriever类型的retriever,如果没有找到,加锁再从缓存里面找一次。这里我们缓存里是没有内容的,所以都不会返回。
接下来调用了retrieveApplicationListeners方法,来遍历所有的监听器。retrieveApplicationListeners方法比较长,我们重点关注下supportsEvent(listener, eventType, sourceType)方法,该方法用来判断是否此监听器关注该事件,过程主要包括,判断此类型是否是GenericApplicationListener类型,如果不是,则构造一个代理,代理的目的是,通过泛型解析,最终获得监听器所感兴趣的事件。
如果经过判断,监听器对该事件是感兴趣的,则此监听器会被加入监听器列表中。
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
当某个事件所有的监听器被收集完毕后,multicastEvent(SimpleApplicationEventMulticaster类)方法会对事件进行传播。即调用监听器的通用触发接口方法:listener.onApplicationEvent(event);这样,就完成了这个事件的传播。
上一篇
到此这篇关于SpringBoot深入分析讲解监听器模式下的文章就介绍到这了,更多相关SpringBoot监听器模式内容请搜索编程学习网以前的文章希望大家以后多多支持编程学习网!
本文标题为:SpringBoot深入分析讲解监听器模式下
基础教程推荐
- java基础知识之FileInputStream流的使用 2023-08-11
- JDK数组阻塞队列源码深入分析总结 2023-04-18
- Java实现查找文件和替换文件内容 2023-04-06
- Java实现线程插队的示例代码 2022-09-03
- Java文件管理操作的知识点整理 2023-05-19
- ConditionalOnProperty配置swagger不生效问题及解决 2023-01-02
- Java数据结构之对象比较详解 2023-03-07
- java实现多人聊天系统 2023-05-19
- springboot自定义starter方法及注解实例 2023-03-31
- Java并发编程进阶之线程控制篇 2023-03-07