<返回更多

spring监听机制

2022-01-06    NeverMore
加入收藏

前言

前一段时间,刚刚接手一个项目,项目中看到使用的spring的事件监听机制,加上之前自己看spring源码的时候也对spring listener 有点影像,于是就重新追一追源码,理一理spring 事件监听机制的工作原理

案例

  1. 自定义event
spring监听机制

 

  1. 自定义listener
spring监听机制

 

  1. 测试推送
spring监听机制

 

  1. 测试结果
spring监听机制

 

一个非常简单的案例,通过定义事件,监听,推送实现了简单的事件监听的流程。

原理分析

  1. 推送事件

通过案例可以看到我们通过
ApplicationContext.publishEvent方法来推送事件,实际是其子类 AbstractApplicationContext 实现的发送操作

spring监听机制

 

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}

通过源码可以看到发送事件最终是交个
ApplicationEventMulticaster来推送。

那么
ApplicationEventMulticaster对象是怎么来的呢,它里面具体是如何推送的呢?我们接着往下看。

读过spring源码的同学一定对
AbstractApplicationContext中的refresh方法很熟悉。这是spring源码的核心部分,而在其中有一步

spring监听机制

 

就是来构造
ApplicationEventMulticaster。

spring监听机制

 

参照源码,我们并没有定义和注册
applicationEventMulticaster,所以就会使用SimpleApplicationEventMulticaster。

spring监听机制

 

在multicastEvent中

1,首先是ResolvableType的确认

spring监听机制

 


spring监听机制

 

可以看到最后是通过Event的class对象作为ResolvableType的属性,后面匹配Listener的时候就是使用这个。

2,通过ResolvableType获取适合的Listener

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);
// Potential new retriever to populate
CachedListenerRetriever newRetriever = null;
// Quick check for existing entry on ConcurrentHashMap
CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
if (existingRetriever == null) {
// Caching a new ListenerRetriever if possible
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;
}
// If result is null, the existing retriever is not fully populated yet by another thread.
// Proceed like caching wasn't possible for this current local attempt.
}
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}

这边这种使用缓存机制的代码,可以在spring源码中多次看到,所以大家可以学习这种方式,提高性能。


retrieveApplicationListeners方法比较大,我这边只截取了部分,可以看到是通过eventType

和sourceType来获取适合的listener。

spring监听机制

 

3,接下来就是调用invokeListener方法来实际操作,这边可以看到可以通过Executor

来实现异步操作。当然比较好的方式还是自己配置线程池,这样可以通过前缀区分出业务。

spring监听机制

 


spring监听机制

 

至此可以看到,调用的是对应listener的onApplicationEvent。

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>