- Spring 监听器listener原理-基本使用(一)
- Spring 监听器listener原理-手写监听器(二)
- Spring 监听器listener原理-spring监听器源码分析(三)
概述
要理解ApplicationListener的实现原理,需要对Spring的扩展点BeanPostProcessor
有一点了解。这个接口是Spring最重要的接口之一,这个接口与Spring Bean的生命周期息息相关,我们常说的实例化前,实例化后,属性注入,初始化前,初始化后等等,其实都是调用了BeanPostProcessor
或它子类的方法。有关于BeanPostProcessor
的简单介绍可以参考文章,spring也是借助于bean的后置处理器查找实现了ApplicationListener的监听器
前面两篇文章中,我们可以总结事件发布大概有如下组件
- 事件广播器,可以理解是我们的
applicationContext
。 - 事件
ApplicationEvent
。 - 事件监听器
ApplicationListener
。
那么Spring是如何找到所有的ApplicationListener以及是如何判断是否是当前监听器感兴趣的事件的,下面将为大家解答。
事件发布者
当Spring容器启动的时候会调用refresh初始化容器
org.springframework.context.support.AbstractApplicationContext#refresh
在refresh会调用initApplicationEventMulticaster进行事件广播器的初始化
@Override
public void refresh() throws BeansException, IllegalStateException {
.........省略
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
.........省略
}
下面代码的逻辑最要是判断容器中是否有名字叫applicationEventMulticaster
的事件广播器,如果有则使用已有的(这也算是Spring的一个扩展点,也就是或如果我们创建了个名字是applicationEventMulticaster
的事件广播器,那么就会使用我们自定义的),如果没有则新建默认的事件广播器SimpleApplicationEventMulticaster
。这里会赋值给applicationEventMulticaster
成员变量。applicationContext
也实现了ApplicationEventPublisher
接口,所以它拥有事件相关的所有方法,但applicationContext
只是一个代理,当我们调用applicationContext.publishEvent
方法时,其实调用的就是applicationEventMulticaster
这个成员变量对象。
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//首先看spring容器中是不是已经有名字为applicationEventMulticaster的对象,
//如果有这使用容器中已有的对象并赋值给applicationEventMulticaster
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
//如果没有则新建一个SimpleApplicationEventMulticaster对象,并赋值给applicationEventMulticaster ;
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
事件发布
事件发布的关键方法流程如下
org.springframework.context.support.AbstractApplicationContext#publishEvent
-->org.springframework.context.support.AbstractApplicationContext#publishEvent
-->org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent //发布事件
-->org.springframework.context.event.AbstractApplicationEventMulticaster#getApplicationListeners //找到感兴趣的事件
-->org.springframework.context.event.AbstractApplicationEventMulticaster#retrieveApplicationListeners//找到感兴趣的事件
-->org.springframework.context.event.AbstractApplicationEventMulticaster#supportsEvent //判断是否是感兴趣的事件
multicastEvent
multicastEvent
方法很简单,调用getApplicationListeners
方法找到所有对当前事件感兴趣的监听器,如果存在线程池,则异步执行监听逻辑,否则同步执行。默认情况下执行事件的逻辑是跟发布事件是同一个线程
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
//getApplicationListeners 方法找到所有的对当前事件感兴趣的监听器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
//如果有配置线程池,则使用线程池执行监听
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
getApplicationListeners
getApplicationListeners
方法,主要是判断缓存中有没有已经缓存好的事件,有则直接返回,没有则调用方法retrieveApplicationListeners
检索监听器。
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
//生成一个缓存key
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);
//没有的话,新建个键值对,并放到map中
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.
}
//缓存中没有调用retrieveApplicationListeners方法查找事件ApplicationEvent。
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
retrieveApplicationListeners
this.defaultRetriever.applicationListeners
和this.defaultRetriever.applicationListenerBeans
存放了所有的Spring事件,最终会调用supportsEvent
方法过滤出对当期事件感兴趣的监听器
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) {
//defaultRetriever.applicationListeners存放了所有的applicationListeners
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
//this.defaultRetriever.applicationListenerBeans存放的是PayloadApplicationEvent事件
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
// Add programmatically registered listeners, including ones coming
// from ApplicationListenerDetector (singleton beans and inner beans).
for (ApplicationListener<?> listener : listeners) {
//判断是否对当期事件感兴趣
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
filteredListeners.add(listener);
}
allListeners.add(listener);
}
}
...............省略
}
这里以this.defaultRetriever.applicationListeners
为例来讲解this.defaultRetriever.applicationListeners
中的监听器是哪里来的。defaultRetriever.applicationListeners
包含的监听器包含两种类:
- 实现了
ApplicationListener
接口。 -
@EventListener
注解
查找实现了ApplicationListener接口的监听器。
这里关键调用ApplicationListenerDetector
的postProcessAfterInitialization
方法(这个方法也就是常说的bean初始化后)和postProcessMergedBeanDefinition
方法。这两个都是BeanPostProcessor
的子类提供的方法。
postProcessMergedBeanDefinition
方法的作用很简单,就是判断这个java类是否实现了ApplicationListener接口,是的话就是一个监听器
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (ApplicationListener.class.isAssignableFrom(beanType)) {
this.singletonNames.put(beanName, beanDefinition.isSingleton());
}
}
postProcessAfterInitialization
方法也很简单从singletonNames
拿到所有的单例ApplicationListener
。
并调用this.applicationContext.addApplicationListener((ApplicationListener<?>) bean)
方法,前面提到过applicationContext
也实现ApplicationEventPublisher
接口,拥有事件发布的所有方法,但实际执行的是赋值给成员变量applicationEventMulticaster
的对象。
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// 拿到所有的单例ApplicationListener并添加到defaultRetriever.applicationListeners
this.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 events
logger.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;
}
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean)
最终执行的方法如下所示。
最终调用this.defaultRetriever.applicationListeners.add(listener)
方法
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
查找加了@EventListener 注解的监听器
查找 加了@EventListener
注解的监听器主要是通过EventListenerMethodProcessor
类,由方法名可以看到,这也是一个bean的后置处理器,但是查找@EventListener
注解的监听器并不是调用bean的后置处理器方法实现的,而是调用SmartInitializingSingleton
的afterSingletonsInstantiated
方法,这个方法会在容器初始化完成之后执行。
查找的方式也很简单粗暴,直接调用beanFactory.getBeanNamesForType(Object.class)
方法获取Spring容器中的所有对象
@Override
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
................省略
try {
processBean(beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}
然后调用processBean
方法,遍历对象中的方法是否有加了EventListener
注解的方法。有则调用DefaultEventListenerFactory
的createApplicationListener
方法创建一个是配置器对象ApplicationListenerMethodAdapter
,构造器参数是方法对象,bean类对象,bean对象。最后调用context.addApplicationListene
r方法把监听器放到this.defaultRetriever.applicationListeners
中
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType) &&
AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
!isSpringContainerClass(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
//遍历对象中的方法是否有加了EventListener注解的方法
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
..............省略..................
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
//调用DefaultEventListenerFactory的 createApplicationListener的方法创建一个适配器类
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
//把监听器添加到this.defaultRetriever.applicationListeners中
context.addApplicationListener(applicationListener);
break;
}
}
}
}
}
查找感兴趣的事件
梳理完监听器的查找过程,最后我们来看看Spring是如何查找感兴趣的事件的。
判断对当前事件的逻辑代码还是比较清晰的,判断当前监听器是不是继承了GenericApplicationListener
。如果不是继承GenericApplicationListene
r的监听器,将会被GenericApplicationListenerAdapter
适配器再次包装。GenericApplicationListener
实现SmartApplicationListener
,SmartApplicationListener
实现了ApplicationListener
接口。但是GenericApplicationListener
的作用是实现了两个SmartApplicationListener
方法。
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));
}
从接口方法可以看到GenericApplicationListener
的子类如果没事重写supportsEventType
方法,就表示对所有的事件感兴趣,通过supportsEventType
方法,我们可以自定义我们感兴趣的事件。
public interface GenericApplicationListener extends SmartApplicationListener {
@Override
default boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return supportsEventType(ResolvableType.forClass(eventType));
}
boolean supportsEventType(ResolvableType eventType);
}
而相对于GenericApplicationListener
接口,适配类GenericApplicationListenerAdapter
实现了supportsEventType
方法,他的默认处理是当期监听器的泛型是不是当期事件或者是当前事件的子类(this.declaredEventType.isAssignableFrom(eventType
))。
public boolean supportsEventType(ResolvableType eventType) {
if (this.delegate instanceof GenericApplicationListener) {
return ((GenericApplicationListener) this.delegate).supportsEventType(eventType);
}
else if (this.delegate instanceof SmartApplicationListener) {
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
}
else {
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
}
}
至此,关于Spring监听器的实现原理已经分析完毕。