Spring中ApplicationListener -【Spring底层原理】(1)

@Test

public void TestMain(){

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

// 自己发布一个事件

applicationContext.publishEvent(new ApplicationEvent(“自己发布的事件”) {

});

applicationContext.close();

}

// ApplicationListener实现类

@Component

public class MyApplicationListener implements ApplicationListener {

// 当容器中发布此事件后,该方法会触发

public void onApplicationEvent(ApplicationEvent applicationEvent) {

System.out.println(“收到的事件:” + applicationEvent);

}

}

// 配置类

@Configuration

@ComponentScan(“listener”)

public class AppConfig {

}

运行启动类,输出结果如下,以下三点说一下:

  • 容器启动时,会执行容器刷新完成事件,也就是ContextRefreshedEvent

  • 容器关闭时,会执行容器关闭事件,也就是ContextClosedEvent

  • 在启动类中,通过publishEvent来发布事件,执行这个方法的时候,ApplicationListener 就能监听到这个事件,就会回调onApplicationEvent执行

image-20210320174351733

三、源码分析

在上面的案例中,收到了三个事件,分别是:ContextRefreshedEventContextClosedEvent以及自己定义的MainTest$1[source=自己发布的事件],这几个事件在底层是如何收到的呢?,我们就通过源码来进行分析,在回掉方法onApplicationEvent打上断点,通过Debug查看源码:

【1】事件发布

通过Debug,我们可以看到,最先收到ContextRefreshedEvent事件,下面咱们就根据方法调用栈分析ContextRefreshedEvent如何发布的

image-20210320201912672

容器创建对象,调用refresh()方法——>finishRefresh()方法——>publishEvent()方法,调用getApplicationEventMulticaster()方法获取事件的多播器,也就是派发器

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {

Assert.notNull(event, “Event must not be null”);

Object applicationEvent;

if (event instanceof ApplicationEvent) {

applicationEvent = (ApplicationEvent)event;

} else {

applicationEvent = new PayloadApplicationEvent(this, event);

if (eventType == null) {

eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();

}

}

if (this.earlyApplicationEvents != null) {

this.earlyApplicationEvents.add(applicationEvent);

} else {

// 获取事件的多播器,也就是派发器

this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);

}

if (this.parent != null) {

if (this.parent instanceof AbstractApplicationContext) {

((AbstractApplicationContext)this.parent).publishEvent(event, eventType);

} else {

this.parent.publishEvent(event);

}

}

}

调用multicastEvent进行事件的派发

  • 获取所有ApplicationListener进行遍历

  • 判断是否可以用executor异步执行,可以的话使用executor进行异步派发,派发的时候我们可以自定义是同步还是异步

  • 否则同步执行派发

public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {

ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);

Executor executor = this.getTaskExecutor();

Iterator var5 = this.getApplicationListeners(event, type).iterator();

while(var5.hasNext()) {

// 获取ApplicationListener进行遍历

ApplicationListener<?> listener = (ApplicationListener)var5.next();

// 判断是否可以用executor异步执行,可以的话使用executor进行异步派发

if (executor != null) {

executor.execute(() -> {

this.invokeListener(listener, event);

});

} else {

// 否则同步执行

this.invokeListener(listener, event);

}

}

}

执行invokeListener方法,拿到listener回调onApplicationEvent方法

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {

try {

// 执行invokeListener方法,拿到listener回调onApplicationEvent方法

listener.onApplicationEvent(event);

} catch (ClassCastException var6) {

String msg = var6.getMessage();

if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {

throw var6;

}

Log logger = LogFactory.getLog(this.getClass());

if (logger.isTraceEnabled()) {

logger.trace("Non-matching event type for listener: " + listener, var6);

}

}

}

【2】获取事件派发器getApplicationEventMulticaster

容器创建对象,调用refresh()方法——>initApplicationEventMulticaster()方法,初始化ApplicationEventMulticaster

  • 先从容器中找是否有ID为“applicationEventMulticaster”的组件

  • 有,则通过getBean的方式获取到该组件

  • 如果没有,则创建一个简单的ApplicationEventMulticaster

  • 将创建的注册到容器的单实例bean中,这样我们就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster

protected void initApplicationEventMulticaster() {

ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();

// 从bean工厂中找是否有ID为“applicationEventMulticaster”的组件

if (beanFactory.containsLocalBean(“applicationEventMulticaster”)) {

// 获取到该组件

this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean(“applicationEventMulticaster”, ApplicationEventMulticaster.class);

if (this.logger.isTraceEnabled()) {

this.logger.trace(“Using ApplicationEventMulticaster [” + this.applicationEventMulticaster + “]”);

}

} else {

// 如果没有则自己创建一个简单的ApplicationEventMulticaster

this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);

// 将创建的注册到容器的单实例bean中

beanFactory.registerSingleton(“applicationEventMulticaster”, this.applicationEventMulticaster);

if (this.logger.isTraceEnabled()) {

this.logger.trace(“No ‘applicationEventMulticaster’ bean, using [” + this.applicationEventMulticaster.getClass().getSimpleName() + “]”);

}

}

}

【3】容器中有哪些监听器

容器创建对象,调用refresh()方法——>registerListeners()方法,注册监听器

  • getApplicationListeners:获取所有Listener

  • 从容器中拿到所有ApplicationListener类型的Listener组件

  • 把组件添加到getApplicationEventMulticaster派发器中,注册到派发器中

protected void registerListeners() {

// 获取所有Listener

Iterator var1 = this.getApplicationListeners().iterator();

while(var1.hasNext()) {

ApplicationListener<?> listener = (ApplicationListener)var1.next();

this.getApplicationEventMulticaster().addApplicationListener(listener);

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

做任何事情都要用心,要非常关注细节。看起来不起眼的、繁琐的工作做透了会有意想不到的价值。
当然要想成为一个技术大牛也需要一定的思想格局,思想决定未来你要往哪个方向去走, 建议多看一些人生规划方面的书籍,多学习名人的思想格局,未来你的路会走的更远。

更多的技术点思维导图我已经做了一个整理,涵盖了当下互联网最流行99%的技术点,在这里我将这份导图分享出来,以及为金九银十准备的一整套面试体系,上到集合,下到分布式微服务

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

更多的技术点思维导图我已经做了一个整理,涵盖了当下互联网最流行99%的技术点,在这里我将这份导图分享出来,以及为金九银十准备的一整套面试体系,上到集合,下到分布式微服务

[外链图片转存中…(img-nHYDv8JG-1713333414087)]

[外链图片转存中…(img-L9bWLZvh-1713333414087)]

[外链图片转存中…(img-76prIuqG-1713333414087)]

[外链图片转存中…(img-mQXWdCRh-1713333414088)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值