@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执行
三、源码分析
在上面的案例中,收到了三个事件,分别是:ContextRefreshedEvent
、ContextClosedEvent
以及自己定义的MainTest$1[source=自己发布的事件]
,这几个事件在底层是如何收到的呢?,我们就通过源码来进行分析,在回掉方法onApplicationEvent打上断点,通过Debug查看源码:
【1】事件发布
通过Debug,我们可以看到,最先收到ContextRefreshedEvent
事件,下面咱们就根据方法调用栈分析ContextRefreshedEvent
如何发布的
容器创建对象,调用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开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
做任何事情都要用心,要非常关注细节。看起来不起眼的、繁琐的工作做透了会有意想不到的价值。
当然要想成为一个技术大牛也需要一定的思想格局,思想决定未来你要往哪个方向去走, 建议多看一些人生规划方面的书籍,多学习名人的思想格局,未来你的路会走的更远。
更多的技术点思维导图我已经做了一个整理,涵盖了当下互联网最流行99%的技术点,在这里我将这份导图分享出来,以及为金九银十准备的一整套面试体系,上到集合,下到分布式微服务
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
更多的技术点思维导图我已经做了一个整理,涵盖了当下互联网最流行99%的技术点,在这里我将这份导图分享出来,以及为金九银十准备的一整套面试体系,上到集合,下到分布式微服务
[外链图片转存中…(img-nHYDv8JG-1713333414087)]
[外链图片转存中…(img-L9bWLZvh-1713333414087)]
[外链图片转存中…(img-76prIuqG-1713333414087)]
[外链图片转存中…(img-mQXWdCRh-1713333414088)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!