这次终于把Spring的监听器讲明白了

简介: 监听器可以在使用过程时监听某些事件的发生,然后对这些事件做出响应处理。监听器对应用场景很多,用户的每一个操作都可以被定义为一个事件,通过监听器就能对某些业务场景中的事件进行监听。Spring中提供了ApplicationListener监听事件,本文会从应用出发讲解Spring的监听器,并逐步深入到源码之中。

听说微信搜索《Java鱼仔》会变更强哦!


本文收录于githubgitee ,里面有我完整的Java系列文章,学习或面试都可以看看哦


(一)Spring中的监听器


监听器可以在使用过程时监听某些事件的发生,然后对这些事件做出响应处理。监听器对应用场景很多,用户的每一个操作都可以被定义为一个事件,通过监听器就能对某些业务场景中的事件进行监听。


Spring中提供了ApplicationListener监听事件,本文会从应用出发讲解Spring的监听器,并逐步深入到源码之中。


(二)监听器的使用


首先自定义一个事件,只需要继承 ApplicationEvent 就可以创建一个自己的事件。


publicclassMyApplicationEventextendsApplicationEvent {
publicMyApplicationEvent(Objectsource) {
super(source);
    }
}

接着定义一个事件监听器,实现当监听到事件后在控制台输出一条消息。

@ComponentpublicclassMyListenerimplementsApplicationListener<MyApplicationEvent> {
@OverridepublicvoidonApplicationEvent(MyApplicationEventapplicationEvent) {
System.out.println("事件:"+applicationEvent.toString());
    }
}

在配置类中增加包扫描地址。

@Configuration@ComponentScan(basePackages="com.javayz.listenerDemo")
publicclassMainConfig {
}

网络异常,图片无法展示
|


通过结果可以发现,除了自定义的事件之外,还有一条Spring自带的事件也被打印出来,修改监听器,只打印自定义的事件:

@ComponentpublicclassMyListenerimplementsApplicationListener<ApplicationEvent> {
@OverridepublicvoidonApplicationEvent(ApplicationEventapplicationEvent) {
if (applicationEventinstanceofMyApplicationEvent){
System.out.println("事件:"+applicationEvent.toString());
        }
    }
}

(三)监听器源码分析:


通过 AnnotationConfigApplicationContext 进入Spring源码内部:

publicAnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
   }

这三个方法是Spring源码的核心,和监听器相关的内容在refresh方法中。进入refresh方法,和监听器相关的三个方法是initApplicationEventMulticaster()、registerListeners()和finishRefresh();


网络异常,图片无法展示
|


首先看initApplicationEventMulticaster()


protectedvoidinitApplicationEventMulticaster() {
ConfigurableListableBeanFactorybeanFactory=getBeanFactory();
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 {
this.applicationEventMulticaster=newSimpleApplicationEventMulticaster(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() +"]");
         }
      }
   }

这一段代码很好理解,首先获取ConfigurableListableBeanFactory工厂,然后判断现在Bean工厂里是否有applicationEventMulticaster,如果有的话就获取该多播器,如果没有就新建一个SimpleApplicationEventMulticaster简单多播器并注册到Bean工厂中,这段代码相当于初始化一个多播器。


接下来是registerListeners()方法:


protectedvoidregisterListeners() {
// Register statically specified listeners first.for (ApplicationListener<?>listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
      }
// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let post-processors apply to them!String[] listenerBeanNames=getBeanNamesForType(ApplicationListener.class, true, false);
for (StringlistenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
      }
// Publish early application events now that we finally have a multicaster...Set<ApplicationEvent>earlyEventsToProcess=this.earlyApplicationEvents;
this.earlyApplicationEvents=null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEventearlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
         }
      }
   }

上面这段注册监听器的代码一共做了三件事情,第一件事情是容器中已有的监听器注册到多播器中;第二件事情是将Bean定义中的事件,也就是我们自己定义的监听器注册到多播器中;第三件事情是发布早期待处理事件,这些早期事件我们定义的监听器是监听不了的,这里发布早期待处理事件时通过multicastEvent()方法进行发布,这个方法会和下面一起讲。


最后看finishRefresh方法,该方法调用的publishEvent方法正式将我们定义的事件发布出去。



protectedvoidfinishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).clearResourceCaches();
// Initialize lifecycle processor for this context.initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.getLifecycleProcessor().onRefresh();
// Publish the final event.publishEvent(newContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.if (!NativeDetector.inNativeImage()) {
LiveBeansView.registerApplicationContext(this);
   }
}

进入publishEvent方法内部,可以看到它的内部同样调用了multicastEvent()方法,说明所有的真正发布动作都是由multicastEvent()完成的。


网络异常,图片无法展示
|


因此我们有必要来看一下multicastEvent()的发布过程,这里的代码也通俗易懂,判断是否有Executor,如果有的话异步加载invokeListener方法,没有的话同步调用invokeListener方法


publicvoidmulticastEvent(finalApplicationEventevent, @NullableResolvableTypeeventType) {
ResolvableTypetype= (eventType!=null?eventType : resolveDefaultEventType(event));
Executorexecutor=getTaskExecutor();
for (ApplicationListener<?>listener : getApplicationListeners(event, type)) {
if (executor!=null) {
executor.execute(() ->invokeListener(listener, event));
      }
else {
invokeListener(listener, event);
      }
   }
}

在invokeListener()方法中,终于看到了熟悉的onApplicationEvent方法,这个方法就是我们在自定义监听器时重写的方法,也正是在这里监听器调用了我们自己定义的onApplicationEvent(),实现了自定义的一些功能。


网络异常,图片无法展示
|


(四)总结


通过代码的实践以及源码的解读,监听的原理其实已经很明朗了,Spring的监听器源码可以算是观察者模式的最佳实践,我建议你照着本文的逻辑看一遍监听器源码,肯定会有新的收获。



相关文章
|
7月前
|
Web App开发 监控 Java
|
25天前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
42 2
Spring高手之路26——全方位掌握事务监听器
|
2月前
|
设计模式 Java Spring
Spring Boot监听器的底层实现原理
Spring Boot监听器的底层实现原理主要基于观察者模式(也称为发布-订阅模式),这是设计模式中用于实现对象之间一对多依赖的一种常见方式。在Spring Boot中,监听器的实现依赖于Spring框架提供的事件监听机制。
35 1
|
7月前
|
NoSQL Java Redis
Spring Boot 监听 Redis Key 失效事件实现定时任务
Spring Boot 监听 Redis Key 失效事件实现定时任务
149 0
|
4月前
|
缓存 Java 数据库
Spring Boot中使用监听器
系统的介绍了监听器原理,以及在 Spring Boot 中如何使用监听器,列举了监听器的三个常用的案例,有很好的实战意义。最后讲解了项目中如何自定义事件和监听器,并结合微服务中常见的场景,给出具体的代码模型,均能运用到实际项目中去,希望读者认真消化。
|
Java Spring
spring boot中提供了一些监听方法,现在我需要在系统启动前完成一些操作。用什么方法实现或者注解?
spring boot中提供了一些监听方法,现在我需要在系统启动前完成一些操作。用什么方法实现或者注解?
|
6月前
|
监控 NoSQL Java
在 Spring Boot 中实现 Redis 的发布/订阅功能可以通过 RedisTemplate 和消息监听器来完成
在 Spring Boot 中实现 Redis 的发布/订阅功能可以通过 RedisTemplate 和消息监听器来完成
342 1
|
7月前
|
Java Spring
flowable 监听器无法获取spring bean ,自动注入bean为null,解决方案
flowable 监听器无法获取spring bean ,自动注入bean为null,解决方案
|
7月前
|
NoSQL Java Redis
Spring boot 实现监听 Redis key 失效事件
【2月更文挑战第2天】 Spring boot 实现监听 Redis key 失效事件
653 0