ApplicationEventPublisher是ApplicationContext的父接口之一。 这接口的作用是:Interface that encapsulates event publication functionality.(用于封装事件发布功能的接口)
在这里我们就看到了,Spring底层对ApplicationEvent事件和PayloadApplicationEvent事件的处理:如果发布的直接就是ApplicationEvent类型的事件,那么就直接转换成ApplicationEvent类型,而如果不是ApplicationEvent类型的事件,那么就是我们所说的Object类型的事件,就会帮我们封装成PayloadApplicationEvent(ApplicationEvent子类),并将Object类型的事件信息存储到payload属性中。在处理完事件的类型后,执行了下面这行重要的代码:
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
其中getApplicationEventMulticaster方法是拿到容器中的事件广播器,然后通过这个事件广播器来进行事件的广播。那么这个事件多播器我们也没有配置创建,是怎么获取的呢?
这就需要看一下Spring容器刷新的9大步当中的initApplicationEventMulticaster初始化事件广播器的方法了,如下:
一看代码,还是Spring的老技巧,有了就用你的,没有我就帮你做一个然后用我的:首先,Spring会查看容器中有没有名称为applicationEventMulticaster的bean对象,如果有的话,就返回这个对象;如果没有的话,Spring就会帮我们new一个SimpleApplicationEventMulticaster的事件广播器对象返回。
所以,我们默认就是走的SimpleApplicationEventMulticaster中的multicastEvent事件广播逻辑,代码如下:
Spring正式通过拿到容器中所有符合当前事件的监听器,然后循环遍历挨个调用onApplicationEvent方法。
@EventListener的实现
除了实现ApplicationListener接口的方式来实现监听器,在走向注解驱动开发后,Spring同样也为我们提供了@EventListener这个注解来实现监听器,注解使用起来还是十分的方便的:
只需要在Spring托管Bean的public方法上加上@EventListener注解就可以监听事件了,想监听的事件类型也可以通过注解的属性来进行配置,例如像这样:就只会监听容器刷新的ContextRefreshedEvent事件。
@EventListener是为了支持注解开发,在Spring Framework 4.2的时候才新增的。我们先不看Spring底层是如何实现的,如果说现在让我们来开发一个注解来实现事件监听的功能,
那你会怎么做呢,如果开始我们和Spring家想的一样:只需要在Spring托管Bean的public方法上加上@EventListener注解就可以监听事件了,而我们又知道Spring的底层是循环遍历
- 支持该事件的监听器集合来进行广播事件的,那么现在为了让我们这个注解也能达到监听事件的效果,即也能被广播到,那么我觉得我们可以想到两种方式来实现:
新建一个集合,将所有标有@EventListener方法的bean都放到这个集合里面,当进行事件广播的时候,同时也循环遍历这个集合,来触发可以监听这个事件的监听器。 - 使用适配器模式,将标有@EventListener注解的方法适配成ApplicationListener(其实,全类名,以及方法名,方法参数都有了,就可以通过反射来执行到适配之前的方法了),然后一起放到Spring储存事件监听器的集合中去。
那么,Spring的底层是采用什么的方式来实现@EventListener能够进行监听的呢?其实,Spring家就是使用第二种适配器模式来完成的,既然我们知道了Spring是使用这种方式实现的,那么我们继续再想想需要在Spring Framework 3.0版本的基础上增加哪些组件呢:
- 我们需要找到所有标有@EventListener方法的bean,其实,就这一问题的解决方案有很多,主要看是在每个bean实例化的过程中就行判断还是说等所有的bean都实例化完了,在最后一起就行判断,而Spring的底层是选择了后者,通过新增一个实现了SmartInitializingSingleton接口的EventListenerMethodProcessor,我们知道在容器刷新快结束的时候,也就是所有的bean都实例化完成之后,Spring会挨个调用SmartInitializingSingleton的afterSingletonsInstantiated方法,Spring也正是在此进行处理标有@EventListener的bean的
- 另外,就是得提供一个适配器,来完成@EventListener注解到ApplicationListener的适配,所以,在SpringFramework 4.2的版本中,引入了ApplicationListenerMethodAdapter这个适配类
- 为了方便构造出ApplicationListenerMethodAdapter这个适配器对象,Spring还新增了一个EventListener工厂类DefaultEventListenerFactory来帮助我们构建ApplicationListenerMethodAdapter对象,或许这就是优秀代码人的代码能力体现吧,是我的话,可能就直接自己new了
上面已经说明了新增了哪些组件了,以及需要新增的原因,下面我们看看EventListenerMethodProcessor以及DefaultEventListenerFactory这两个组件是什么时候注入到容器中的,在容器构造函数中,创建AnnotatedBeanDefinitionReader对象的时候调用registerAnnotationConfigProcessors方法进行了注入,代码如下:
看着两个if写在最后,我们就猜得到是后期为了支持注解@EventListener而后加上去的,只要我们自己没有注入名字为org.springframework.context.event.internalEventListenerProcessor以及名字为org.springframework.context.event.internalEventListenerFactory的bean定义信息的时候,Spring就会帮我们注入EventListenerMethodProcessor以及DefaultEventListenerFactory这两个类型的bean定义信息,
从而在后期帮忙实现@EventListener监听的功能,下面就来大致看看具体是如何实现的吧:
首先来看看EventListenerMethodProcessor的afterSingletonsInstantiated方法:
这个方法,是完成spring容器中beanDefinitionMap转换为spring容器中的bean这步的关键方法,这个方法中,可以分为两部分
1.将beanDefinitionMap中的beanDefinition转换为bean,放入到spring容器中
2.在初始化完成之后,调用smartSingleton.afterSingletonsInstantiated();
所以,我们可以认为,对于@EventListener注解的解析,就是在这里被调用的:
org.springframework.context.event.EventListenerMethodProcessor#afterSingletonsInstantiated
@Override
public void afterSingletonsInstantiated() {
/**
* 1.获取到所有的eventListenerFactory,理论上就是DefaultEventListenerFactory
*/
List<EventListenerFactory> factories = getEventListenerFactories();
ConfigurableApplicationContext context = getApplicationContext();
/**
* 2.获取到spring容器中,所有的beanName,依次遍历
*/
String[] beanNames = context.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
type = AutoProxyUtils.determineTargetClass(context.getBeanFactory(), beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (type != null) {
if (ScopedObject.class.isAssignableFrom(type)) {
try {
Class<?> targetClass = AutoProxyUtils.determineTargetClass(
context.getBeanFactory(), ScopedProxyUtils.getTargetBeanName(beanName));
if (targetClass != null) {
type = targetClass;
}
}
catch (Throwable ex) {
// An invalid scoped proxy arrangement - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
}
}
}
/**
* 从for循环开始,到这里,代码的细节没有看的太懂,但是这段代码是为了获取到beanName对应的type
* ,以便在下面使用
*/
try {
processBean(factories, beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}
processBean的代码逻辑
/**
* 在这个方法中,会解析beanName对应的bean中所有的方法上,是否有添加@EventListener注解,如果有添加
* 则根据beanName生成一个applicationListener,并添加到多事件派发器上
* @param factories
* @param beanName
* @param targetType
*/
protected void processBean(
final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {
/**
* 1.nonAnnotatedClasses
* 这个set集合,可以理解为是一个缓存,全局搜索了下,只有在下面,annotatedMethods为null的时候,才会写入到这个集合中
* 所以,我认为,在第一次解析的时候,如果一个bean中的method没有条件@EventListener注解,就会把这个bean
* 添加到nonAnnotatedClasses集合中
*/
if (!this.nonAnnotatedClasses.contains(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
/**
* 2.解析targetType这个class,获取类中所有加了@EventListener注解的method
*/
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
catch (Throwable ex) {
// An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
}
}
/**
* 3.如果当前class的方法中,没有添加@EventListener注解,就添加到nonAnnotatedClasses中
*/
if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {
// Non-empty set of methods
/**
* 4.如果当前targetClass中,有方法添加了@EventListener注解,那就根据beanName
* 生成一个applicationListener
* 方法,点进去看,会发现,就是ApplicationListenerMethodAdapter这个类
*
* 所以,我们可以认为:
* 1、对于实现ApplicationListener接口这种方式声明的事件监听器,其applicationListener就是对应的实现类
* 2、对于使用@EventListener注解这种方法,其applicationListener就是ApplicationListenerMethodAdapter
*/
ConfigurableApplicationContext context = getApplicationContext();
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
// 这里生成的applicationListener
// 是ApplicationListenerMethodAdapter
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
/**
* 5.最重要得一步:将applicationListener
* 添加到多事件派发器中,在后面publishEvent的时候会用到
*/
context.addApplicationListener(applicationListener);
break;
}
}
}
if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
beanName + "': " + annotatedMethods);
}
}
}
}
保存事件监听器
context.addApplicationListener(applicationListener);
这一行代码,就是来保存事件监听器的
org.springframework.context.support.AbstractApplicationContext#addApplicationListener
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
Assert.notNull(listener, "ApplicationListener must not be null");
if (this.applicationEventMulticaster != null) {
// 将事件监听器存入到多事件派发器的集合中
this.applicationEventMulticaster.addApplicationListener(listener);
}
this.applicationListeners.add(listener);
}
在这个方法中,我们只需要关注一行代码
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
// 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();
}
}
所以,我们可以看到,对于这里的逻辑,其实就是存到了内存中的一个set集合
调用事件监听器
在前面解析完了事件监听器之后,并且也存入到了set集合中,最后会在spring容器刷新完成之后,统一调用事件监听器的方法
org.springframework.context.support.AbstractApplicationContext#finishRefresh
org.springframework.context.support.AbstractApplicationContext#publishEvent(org.springframework.context.ApplicationEvent)
org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
/**
* 获取所有的事件监听器,判断是否是异步执行
* 但是下面这一步getApplicationListeners()是比较重要的一个方法,获取所有的listener
* 我们可以暂时认为是从前面的set集合中获取到对应的事件监听器
*/
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
根据上面的代码,我们了解了Spring底层的处理逻辑是:首先拿到容器中的所有bena对象的名称,然后遍历没一个对象进行判断它是否有标有@EventListener注解的方法,有的话就存储起来,最后来遍历具有@EventListener注解的方法的bean,通过适配器工厂EventListenerFactory将其适配为ApplicationListener对象,最后放入到监听器集合中。你看是不是和我们前面想的方案二是一样的所以说,当我们掌握了Spring的扩展点后,自己来完成一些新的功能也是没有问题的。
事件使用:https://blog.csdn.net/qq_37171353/article/details/115767381
发布流程:https://blog.csdn.net/ITlikeyou/article/details/124773814
监听加载流程:https://blog.csdn.net/CPLASF_/article/details/119118520