Spring事件机制
注:文章基于江南一点雨spring讲解总结而来。
Spring事件是一种基于Spring框架的事件驱动编程模型,它可以让开发者在应用程序中发布和监听事件。Spring事件的实现原理是基于观察者模式,也可以看作是一种发布订阅模式的变体。
观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当主题对象的状态发生变化时,它会通知所有观察者对象,使它们能够自动更新自己。发布订阅模式是一种消息传递模式,它定义了一种一对多的通信机制,让多个订阅者对象同时订阅某一个主题,当主题有新的消息时,它会通知所有订阅者对象,使它们能够接收到消息。
基本用法
Spring事件的定义包括以下几个步骤:
- 定义一个事件类,继承自
org.springframework.context.ApplicationEvent
,并添加一些自定义的属性和方法。 - 定义一个事件监听器类,实现
org.springframework.context.ApplicationListener
接口,或者使用@EventListener
注解标注一个方法,指定要监听的事件类型。 - 在事件源组件中,使用
org.springframework.context.ApplicationEventPublisher
接口的publishEvent
方法发布事件对象。 - 在事件监听器组件中,实现
onApplicationEvent
方法或者注解方法,处理接收到的事件对象。
定义事件的类型
首先需要定义事件类型。事件类型分为两种:一种是直接继承自ApplicationEvent类,另一种是普通的Java类:
法一:继承ApplicationEvent类
public class MyEvent extends ApplicationEvent {
private String name;
private String author;
//这个参数即为事件的源,即这个事件由谁来发起的
public MyEvent(Object source) {
super(source);
}
@Override
public String toString() {
return "MyEvent{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
}
法二:普通Java类
public class Book {
private String name;
private String author;
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
}
定义事件的消费者/监听器
事件消费者有两种不同的定义,可以通过实现接口的方式来定义,也可以通过注解的方式来定义。
法一:实现接口
@Component
public class EventListener implements ApplicationListener<MyEvent> {
//类似于过滤器,只有MyEvent类才会进行处理
@Override
public void onApplicationEvent(MyEvent event) {
System.out.println("收到事件1:"+event);
}
}
法二:注解
@Component
public class MyBookEventListener {
//注解中的泛型即表示监听的事件类型,只针对Book
@EventListener(Book.class)
public void onApplicationEvent(Book book) {
System.out.println("收到事件2" + book);
}
//Object处理各种类型事件
@EventListener
public void onApplicationEvent(Object object) {
System.out.println("收到事件3" + object);
}
}
事件的发布
事件有专门的发布器ApplicationEventPublisher, 但ApplicationContext已经实现了这个发布器,即可以直接通过ApplicationContext去发布事件:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
MyEvent myEvent=new MyEvent(Main.class);
myEvent.setName("三国演义");
myEvent.setAuthor("罗贯中");
context.publishEvent(myEvent);
Book book=new Book();
book.setName("水浒传");
book.setAuthor("施耐庵");
context.publishEvent(book);
}
}
打印结果:
收到事件3
org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@402a079c, started on Wed Nov 22 16:38:14 CST 2023]
收到事件1:MyEvent{name='三国演义', author='罗贯中'}
收到事件3MyEvent{name='三国演义', author='罗贯中'}
收到事件2Book{name='水浒传', author='施耐庵'}
收到事件3Book{name='水浒传', author='施耐庵'}
//可以看到Object类型消费了ContextRefreshedEvent,MyEvent,Book
事件处理机制
默认情况下,事件是==同步(阻塞)==的,即当一个事件发布出去之后,必须等到消费完成后,事件发布方的代码才会继续进行,可以通过打印线程名称去印证。
事件也可以==异步(非阻塞)==处理机制,需要自己去配置一个线程池:
@Configuration
@ComponentScan
public class JavaConfig {
/**
* 向 Spring 容器中注册一个事件广播器,事件广播器的接口是 ApplicationEventMulticaster,这个事件广播器只有一个实现类 SimpleApplicationEventMulticaster
* 所以只能向 Spring 中注册 SimpleApplicationEventMulticaster
* ApplicationEventMulticaster 就是用来广播事件的,默认情况下,Spring 容器在启动的时候,会去自动查找一个名为 applicationEventMulticaster 的事件广播器,
* 如果找到了,就直接使用这个事件广播器,如果没有找到,则自动创建一个 SimpleApplicationEventMulticaster 类型的事件广播器。
* 所以,如果我们想要自定义事件广播器,则自定义的事件广播器的名字必须是 applicationEventMulticaster。
*
* @return
*/
@Bean
ApplicationEventMulticaster applicationEventMulticaster() {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
taskExecutor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 5);
taskExecutor.setQueueCapacity(Runtime.getRuntime().availableProcessors() * 2);
taskExecutor.initialize();
multicaster.setTaskExecutor(taskExecutor);
return multicaster;
}
//建了一个SimpleApplicationEventMulticaster的实例对象,并同时创建了一个ThreadPoolTaskExecutor的实例对象。接着,通过设置ThreadPoolTaskExecutor的核心线程池大小为可用处理器数、最大线程池大小为可用处理器数的5倍、队列容量为可用处理器数的2倍,并调用initialize()方法来初始化线程池。然后,将SimpleApplicationEventMulticaster的taskExecutor属性设置为ThreadPoolTaskExecutor对象,最后返回SimpleApplicationEventMulticaster对象。
}
ApplicationEventMulticaster 的初始化过程:当容器初始化的时候,会调用到 refresh 方法,在该方法中会调用 initApplicationEventMulticaster 方法,而这个方法就是用来初始化事件广播器的。
protected void initApplicationEventMulticaster() {
//获取到容器
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//查询当前容器中是否存在名为 applicationEventMulticaster 的 Bean
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
//如果存在,则获取到这个 Bean,并赋值给 applicationEventMulticaster 变量,这个就是事件广播器,
//接下来的事件广播就通过 applicationEventMulticaster 对象来完成
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
//容器中不存在名为 applicationEventMulticaster 的 Bean,那么就现场 new 一个事件广播器
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
//将现场 new 的 Bean 手动注册到 Spring 容器中。
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() + "]");
}
}
}
从这里不难看出,Spring 容器在启动的时候,会去自动查找一个名为 APPLICATION_EVENT_MULTICASTER_BEAN_NAME的字符常量即applicationEventMulticaster 的事件广播器,如果找到了,就直接使用这个事件广播器,如果没有找到,则自动创建一个 SimpleApplicationEventMulticaster (唯一实现)类型的事件广播器。
事件监听器注册方式
默认情况下,无论使用哪种方式定义的事件监听器,都必须要注册到 Spring 容器中,才会起作用。当然,Spring 中也提供了事件监听器不注册的方式:
public class Demo {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
ctx.addApplicationListener(new MyEventListener());
//发布事件方法
MyEvent myEvent = new MyEvent(Demo.class);
myEvent.setName("张三");
myEvent.setGender("男");
ctx.publishEvent(myEvent);
Book book = new Book();
book.setName("三国演义");
book.setPrice(22.0);
//发布 book 类型的事件
ctx.publishEvent(book);
System.out.println("Demo>>>Thread.currentThread().getName() = " + Thread.currentThread().getName());
}
}
这种手动注册的方式有一个局限性,就是只能添加 ApplicationListener 类型的事件监听器,,无法添加通过注解定义的事件监听器。
public class EventListener implements ApplicationListener<MyEvent>
原理分析
事件消费者
Spring容器中事件监听器可以分为三种:
- 注册到Spring容器中的bean
- @EventListener注解定义的消费者
- 直接ctx.addEventListener()方法存到事件广播器
三种方法处理流程有所差异
注册到Spring容器中的bean
在spring容器初始化的时候会调用refresh()方法,在refresh()方法中会调用到registerListeners()方法来注册所有的事件监听器。事件是ApplicationContext里面增强的功能,defaultListableBeanFactory没有这个功能。
//org.springframework.context.support.AbstractApplicationContext#registerListeners
protected void registerListeners() {
// 这个就是遍历所有静态注入的事件监听器,在前面的案例中,没有把事件监听器注册到容器中,直接调用 addApplicationListener 方法添加的监听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
//这里就获取到事件发布器,然后为之添加事件监听器
getApplicationEventMulticaster().addApplicationListener(listener);
}
//这里就是从 Spring 容器中找到所有 ApplicationListener 类型的 Bean,此时 Bean 还没有初始化,所以只能先拿到 beanName
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
//遍历 beanName,将之添加到 ApplicationEventMulticaster 中
//这些 beanName,将来会在 BeanPostProcessor 中进行处理,即在 BeanPostProcessor 中,会去判断当前创建成功的 Bean 是否是一个 ApplicationListener
//如果是,则调用 addApplicationListener 方法将之存储起来
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
//如果有需要提前处理的事件,现在就可以在这个地方去发布了
//直接处理直接发布了,不需要后面在其他地方去发布
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
这里的只是将事件监听器的beanName记录了起来,只是一个名单。Bean在spring容器中正常初始化完成后,后置处理器ApplicationListenerDetetor会对初始化完成的Bean做进一步处理。
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//首先判断当前 bean 的类型是否是 ApplicationListener
if (ApplicationListener.class.isAssignableFrom(beanType)) {
//如果是,将当前 bean 是否单例,存入到 singletonNames 中
this.singletonNames.put(beanName, beanDefinition.isSingleton());
}
}
//这是后置处理器,在 postProcessMergedBeanDefinition 方法之后执行
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
//判断当前 bean 是否是一个 ApplicationListener
if (bean instanceof ApplicationListener<?> applicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
//如果是 ApplicationListener,则读取当前 bean 是否单例
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
//如果是单例,则将之添加到事件发布器中
this.applicationContext.addApplicationListener(applicationListener);
}
else if (Boolean.FALSE.equals(flag)) {
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
//内部bean inner bean top-level
// 内部Bean如果是非singleton类型则无法作为监视器,除非内部bean是top-level才行即bean注册的时候放在最上面
// 外部bean作为非singleton类型是可以作为事件监听器
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.");
}
//移除beanName
this.singletonNames.remove(beanName);
}
}
return bean;
}
通过上述流程就能将ListenerBean收集起来。
@EventListener注解定义的消费者
当所有Bean都初始化完成之后,就会去处理注解定义的事件监听器
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof SmartFactoryBean<?> smartFactoryBean && smartFactoryBean.isEagerInit()) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
//在上面的 for 循环执行完毕之后,只要不是懒加载的 bean,现在都已经被初始化了
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {
StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
//这个方法就会去处理那些通过注解定义的事件监听器
smartSingleton.afterSingletonsInstantiated();
smartInitialize.end();
}
}
}
@Override
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
//从 Spring 容器中查询所有的 beanName
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
//这个 bean 是否不是 scope 注解产生的代理
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
//确定当前 bean 的类型,由于这个 bean 可能是代理对象,determineTargetClass 方法则可以穿透层层迷雾,找到最终被代理的对象
type = AutoProxyUtils.determineTargetClass(beanFactory, 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(
beanFactory, 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);
}
}
}
try {
//这个就是去处理 bean
processBean(beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "': " + ex.getMessage(), ex);
}
}
}
}
}
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType) &&
AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
!isSpringContainerClass(targetType)) {
//在 if 中判断当前类有 EventListener 注解
//由于当前类中可能存在多个方法都被注解标记了,这里定义 Map,将这些被注解标记的方法统一收集起来
Map<Method, EventListener> annotatedMethods = null;
try {
//在当前类上,查找所有添加了 @EventListener 注解的方法,并将查询结果赋值给 annotatedMethods
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);
}
}
if (CollectionUtils.isEmpty(annotatedMethods)) {
//如果当前类上没有添加 @EventListener 注解的方法,则将当前类加入到 nonAnnotatedClasses 集合中
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {
//当前类中确实有方法添加了 @EventListener 注解,那么就在这里来处理
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
//EventListenerFactory 这个类主要是用来解析 @EventListener 注解的,但是 EventListenerFactory 是一个接口,该接口只有一个实现类
//DefaultEventListenerFactory,所以最终都是由 DefaultEventListenerFactory 来解析 @EventListener 注解的
// TransactionalEventListenerFactory也实现了该接口
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
//遍历前面查询到的所有方法
for (Method method : annotatedMethods.keySet()) {
//遍历 factories,但是这里实际上就只有一个对象
for (EventListenerFactory factory : factories) {
//首先会去判断这个 factory 是否支持当前的方法处理
if (factory.supportsMethod(method)) {
//查找到方法本身
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
//这里创建了一个 ApplicationListener,这个其实是 ApplicationListenerMethodAdapter
//从这里我们可以看到,无论我们是直接定义的Java 类,还是通过注解定义的事件监听器,反正最终都会是一个 ApplicationListener 的实例
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
//进行初始化
if (applicationListener instanceof ApplicationListenerMethodAdapter alma) {
alma.init(context, this.evaluator);
}
//将监听器添加到事件广播器中
context.addApplicationListener(applicationListener);
break;
}
}
}
if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
beanName + "': " + annotatedMethods);
}
}
}
}
当Bean在初始化完成后就会去检查所有的Bean,检查该Bean是否有@EventListener注解标记的方法,如果有这个方法和注解内容就会被解析为一个ApplicationMethodAdapter(本质上就是ApplicationListener),并注册到广播器中。
流程图
事件监听器
ApplicationEventMulticaster:ApplicationEventMulticaster 接口只有一个实现类SimpleApplicationEventMulticaster
public interface ApplicationEventMulticaster {
//添加事件监听器,无论我们通过何种方式配置的事件监听器,最终都是要统一收集在 ApplicationEventMulticaster 中
//因为所谓的事件广播(事件发布)就是在当前接口中完成的,发布事件的时候,就从收集到的所有的事件监听器中,找到合适的事件监听器去处理当前事件
void addApplicationListener(ApplicationListener<?> listener);
//这个也是添加事件监听器,但是这里是添加 Spring 容器中 Bean 的名称
//默认情况下,Spring 容器收集事件监听器的时候,Spring 容器中的 Bean 都还没有初始化,所以此时还不能存具体的 Bean,只能先存 beanName 进来
void addApplicationListenerBean(String listenerBeanName);
//移除 Spring 中的监听器
void removeApplicationListener(ApplicationListener<?> listener);
//移除监听器的 beanName
void removeApplicationListenerBean(String listenerBeanName);
//根据条件批量移除事件监听器
void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate);
//根据条件批量移除事件监听器名称
void removeApplicationListenerBeans(Predicate<String> predicate);
//移除所有
void removeAllListeners();
//事件发布
void multicastEvent(ApplicationEvent event);
//事件发布,第二个参数是事件类型
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
事件发布器
ApplicationEventPublisher
一般我们都是调用 ApplicationContext 中的事件发布方法,这里的事件发布方法实际上是由 ApplicationEventPublisher 来统一定义的:
@FunctionalInterface
public interface ApplicationEventPublisher {
//发布一个 ApplicationEvent 类型的事件,但是在具体的发布过程中,会将这个事件转为 Object 类型
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
//最终事件发布都是调用这个方法,即无论何种类型的事件,统一都当作 Object 对象来处理
void publishEvent(Object event);
}
但是这个接口其实并不真正的去发布事件,这个接口中的方法只是做一些事件发布之前的准备工作,真正的事件发布还是委托给事件广播器去做的。
上面两个接口的方法,最终都是调用到如下方法:
//这个方法有两个参数,第一个是事件对象;第二个参数则是事件类型
protected void publishEvent(Object event, @Nullable ResolvableType typeHint) {
Assert.notNull(event, "Event must not be null");
ResolvableType eventType = null;
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
//首先判断事件是否为 ApplicationEvent 类型
if (event instanceof ApplicationEvent applEvent) {
applicationEvent = applEvent;
eventType = typeHint;
}
else {
//说明不是 ApplicationEvent 类型,可能是一个 Book 类型或者其他自定义的 Java 类
ResolvableType payloadType = null;
if (typeHint != null && ApplicationEvent.class.isAssignableFrom(typeHint.toClass())) {
eventType = typeHint;
}
else {
payloadType = typeHint;
}
//此时 payloadType 为 null,但是大家从这里可以看到,对于自定义的普通 Java 类来说,最终都会被封装为一个 PayloadApplicationEvent 对象
//所以无论是继承自 ApplicationEvent 还是自定义的普通 Java 类,最终都是 ApplicationEvent
applicationEvent = new PayloadApplicationEvent<>(this, event, payloadType);
}
// Determine event type only once (for multicast and parent publish)
if (eventType == null) {
//如果此时依然没有确定事件的类型,就从事件对象中解析出来事件类型
eventType = ResolvableType.forInstance(applicationEvent);
if (typeHint == null) {
typeHint = eventType;
}
}
//如果 earlyApplicationEvents 不为空,先把事件对象放到这个集合中
// 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) {
abstractApplicationContext.publishEvent(event, typeHint);
}
else {
this.parent.publishEvent(event);
}
}
}
ApplicationEventMulticaster
@Override
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
//如果传入了事件类型,则直接使用,否则就从事件对象中解析出来事件类型
ResolvableType type = (eventType != null ? eventType : ResolvableType.forInstance(event));
//获取线程池,系统自动配置的 SimpleApplicationEventMulticaster 是没有这个线程池的,如果想要这个线程池,可以自己配置,配置之后,这里就能拿到线程池
Executor executor = getTaskExecutor();
//调用 getApplicationListeners 方法去查询所有满足条件的事件监听器,然后遍历所有的事件监听器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
//如果存在线程池
if (executor != null) {
//就在线程池中去执行事件监听器,这就是我们前面视频所讲的异步非阻塞监听器
executor.execute(() -> invokeListener(listener, event));
}
else {
//如果没有配置线程池,那么就直接在这里执行,这就是阻塞的事件监听器
invokeListener(listener, event);
}
}
}
//监听器执行方法
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
(event instanceof PayloadApplicationEvent payloadEvent &&
matchesClassCastMessage(msg, payloadEvent.getPayload().getClass()))) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception.
Log loggerToUse = this.lazyLogger;
if (loggerToUse == null) {
loggerToUse = LogFactory.getLog(getClass());
this.lazyLogger = loggerToUse;
}
if (loggerToUse.isTraceEnabled()) {
loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
执行事件监听器方法实际上就是调用事件监听器的 onApplicationEvent 方法,对于通过注解定义的事件监听器,也是调用该方法。因为根据前面的分析,凡是通过注解标记的事件监听器,最终都会被解析为 ApplicationListenerMethodAdapter 对象,这个对象中,保存了注解标记的方法对象,在这个对象的 onApplicationEvent 方法中,会查找到 bean 对象,然后通过反射区调用 method 方法。
getApplicationListeners:这个方法就是根据事件类型去查找到合适的事件监听器:
protected Collection<ApplicationListener<?>> getApplicationListeners(
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
/**
* Actually retrieve the application listeners for the given event and source type.
* @param eventType the event type
* @param sourceType the event source type
* @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)
* @return the pre-filtered list of application listeners for the given event and source type
*/
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);
//所有的事件监听器的 bean
Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
//this.defaultRetriever.applicationListeners 中保存的是,Spring 容器在初始化的时候,就已经处理成 ApplicationListener 的所有 Bean
//this.defaultRetriever.applicationListenerBeans 中保存的是,Spring 容器在初始化的时候,记录下来的所有的 ApplicationListener 的 beanName
synchronized (this.defaultRetriever) {
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
// Add programmatically registered listeners, including ones coming
// from ApplicationListenerDetector (singleton beans and inner beans).
//首先处理那些已经是 ApplicationListener 对象的 bean,这些 bean 基本上都是来自 Bean 的后置处理器 ApplicationListenerDetector
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
filteredListeners.add(listener);
}
allListeners.add(listener);
}
}
// Add listeners by bean name, potentially overlapping with programmatically
// registered listeners above - but here potentially with additional metadata.
//如果 listenerBeans 不为空,说明还要要处理的 beanName
//这个集合中的数据,是 Spring 容器在一开始初始化的时候就收集好的,这个集合中保存的所有 beanName,有可能已经在 ApplicationListenerDetector 中
//被处理过了(单例的事件监听器),也有可能还没有被处理(多例的外部 Bean);
if (!listenerBeans.isEmpty()) {
ConfigurableBeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
//allListeners 中不包含当前 listener,说明 bean 还没有被处理,那么就在此处处理
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
//如果是单例的,就保存 bean 对象,如果不是单例的,就保存 beanName 多个示例Bean的hashCode不一样,Set没用还是会存进去。
//如果不区分是否单例,都使用对象,那么对于非单例的监听器,可能就保存了多份
//对于多例的 bean,beanName 字符串不会多次保存,所以对于多例的 bean,就保存其 listenerBeanName
if (beanFactory.isSingleton(listenerBeanName)) {
filteredListeners.add(listener);
}
else {
filteredListenerBeans.add(listenerBeanName);
}
}
allListeners.add(listener);
}
}
else {
// Remove non-matching listeners that originally came from
// ApplicationListenerDetector, possibly ruled out by additional
// BeanDefinition metadata (e.g. factory method generics) above.
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
filteredListeners.remove(listener);
}
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
//最后给所有监听器排序
AnnotationAwareOrderComparator.sort(allListeners);
//有缓存对象
if (retriever != null) {
if (filteredListenerBeans.isEmpty()) {
//filteredListenerBeans 为空表示没有多例的监听器,那么此时 allListeners 中保存的就都是单例监听器,只有单例的监听器
retriever.applicationListeners = new LinkedHashSet<>(allListeners);
retriever.applicationListenerBeans = filteredListenerBeans;
}
else {
//如果有多例的 bean,那么此时 allListeners 中就存在多例的监听器,那么这里使用 filteredListeners,这里保存的都是单例的 bean
retriever.applicationListeners = filteredListeners;
retriever.applicationListenerBeans = filteredListenerBeans;
}
}
return allListeners;
}
最终判断一个事件监听器是否是满足条件的事件监听器,要调用它的 supportsEvent 方法,这方法的核心逻辑就是去判断事件类型是否满足条件:
1事件监听器没有指定事件类型,那就意味着所有事件都能处理。
2事件监听器指定了事件类型,那么就去判断事件监听器指定的事件类型和事件类型相匹配。
supportsEvent 一共有三个重载方法:
//这个方法可以理解为是一个初步校验的方法,当这个方法校验通过之后,最终还会去调用第三个重载方法
private boolean supportsEvent(
ConfigurableBeanFactory beanFactory, String listenerBeanName, ResolvableType eventType) {
//根据 beanName 确定 bean 的类型
Class<?> listenerType = beanFactory.getType(listenerBeanName);
if (listenerType == null || GenericApplicationListener.class.isAssignableFrom(listenerType) ||
SmartApplicationListener.class.isAssignableFrom(listenerType)) {
return true;
}
if (!supportsEvent(listenerType, eventType)) {
return false;
}
try {
BeanDefinition bd = beanFactory.getMergedBeanDefinition(listenerBeanName);
//这个是获取这个 BeanDefinition 上的泛型信息
ResolvableType genericEventType = bd.getResolvableType().as(ApplicationListener.class).getGeneric();
//没有指定泛型(能处理所有)或者指定的泛型就是事件类型
return (genericEventType == ResolvableType.NONE || genericEventType.isAssignableFrom(eventType));
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore - no need to check resolvable type for manually registered singleton
return true;
}
}
protected boolean supportsEvent(Class<?> listenerType, ResolvableType eventType) {
//从事件监听器中提取出来声明的要处理的事件类型
ResolvableType declaredEventType = GenericApplicationListenerAdapter.resolveDeclaredEventType(listenerType);
//如果 declaredEventType == null,说明事件监听器本身就没有指定要处理的事件类型,那就是说这个事件监听器可以处理所有的事件类型
//事件监听器指定了类型,那么就指定的类型等于事件类型 eventType
return (declaredEventType == null || declaredEventType.isAssignableFrom(eventType));
}
//如果前面的 supportsEvent 执行通过,最终还会调用这个方法去判断
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener gal ? gal :
new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
- 第一个重载版本:这个版本的
supportsEvent
函数接收一个ConfigurableBeanFactory
,一个监听器的 bean 名称,和一个ResolvableType
事件类型作为参数。这个函数首先获取监听器的类型,然后检查它是否是GenericApplicationListener
或SmartApplicationListener
的实例。如果是,函数就返回true
。如果不是,函数就调用第二个重载版本的supportsEvent
函数。这个版本的好处是它可以处理多种类型的监听器,并且可以根据监听器的类型来决定是否支持特定的事件类型。 - 第二个重载版本:这个版本的
supportsEvent
函数接收一个监听器类型和一个ResolvableType
事件类型作为参数。这个函数从监听器中提取出声明的要处理的事件类型,然后检查这个类型是否等于事件类型eventType
。如果等于,或者监听器没有指定要处理的事件类型(这意味着它可以处理所有的事件类型),函数就返回true
。这个版本的好处是它可以处理那些没有明确指定要处理的事件类型的监听器。 - 第三个重载版本:这个版本的
supportsEvent
函数接收一个ApplicationListener
,一个ResolvableType
事件类型,和一个可选的源类型作为参数。这个函数首先检查监听器是否是GenericApplicationListener
的实例。如果是,它就直接使用这个实例。如果不是,它就创建一个新的GenericApplicationListenerAdapter
实例。然后,函数检查这个监听器是否支持事件类型eventType
和源类型sourceType
。如果都支持,函数就返回true
。这个版本的好处是它可以处理那些需要对源类型进行检查的情况。