Spring 监听器listener原理

Spring 监听器listener原理

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> 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> 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> retrieveApplicationListeners(

ResolvableType eventType, @Nullable Class sourceType, @Nullable CachedListenerRetriever retriever) {

List> allListeners = new ArrayList<>();

Set> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);

Set filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);

Set> listeners;

Set 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.addApplicationListener方法把监听器放到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 annotatedMethods = null;

try {

//遍历对象中的方法是否有加了EventListener注解的方法

annotatedMethods = MethodIntrospector.selectMethods(targetType,

(MethodIntrospector.MetadataLookup) method ->

AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));

}

..............省略..................

// Non-empty set of methods

ConfigurableApplicationContext context = this.applicationContext;

Assert.state(context != null, "No ApplicationContext set");

List 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。如果不是继承GenericApplicationListener的监听器,将会被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 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 eventClass = (Class) eventType.resolve();

return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));

}

else {

return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));

}

}

至此,关于Spring监听器的实现原理已经分析完毕。

相关文章

地府应该怎么玩?这些细节必须注意
365bet现场滚球

地府应该怎么玩?这些细节必须注意

📅 07-15 👁️ 9594
言字旁加一个化是什么字,言字旁加一个化念什么
beat365官方网站登录

言字旁加一个化是什么字,言字旁加一个化念什么

📅 09-29 👁️ 4208
元稹《晚秋》原文及翻译
365bet现场滚球

元稹《晚秋》原文及翻译

📅 10-07 👁️ 3886