Spring事件监听机制
前言
Spring中的事件机制其实就是设计模式中的观察者模式,主要由以下角色构成:
- 事件
- 事件监听器(监听并处理事件)
- 事件发布者(发布事件)
首先看一下监听器和发布者的接口定义
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
}
事件流转流程
初始化事件广播器
看一下这个方法AbstractApplicationContext.refresh,在IOC源码解析那篇文章已经把这个方法分析完了,所以直接关注事件广播器和事件发布相关的逻辑即可
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// 初始化事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// 发布事件
finishRefresh();
}
catch (BeansException ex) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
可以看到如果没有自定义的事件广播器,默认是使用SimpleApplicationEventMulticaster的
发布事件
发布事件是在bean的初始化之后的
protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// 发布事件
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
public void publishEvent(ApplicationEvent event) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
//1. 获取到事件广播器,发布事件
getApplicationEventMulticaster().multicastEvent(event);
//2. 如果存在父容器,父容器也将发布事件
if (this.parent != null) {
this.parent.publishEvent(event);
}
}
具体的发布逻辑在multicastEvent方法中
public void multicastEvent(final ApplicationEvent event) {
//遍历执行listener,getApplicationListeners调用AbstractApplicationEventMulticaster父类方法
for (final ApplicationListener listener : getApplicationListeners(event)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
listener.onApplicationEvent(event);
}
});
}
else {
listener.onApplicationEvent(event);
}
}
}
可以看到也没啥特殊的,无非就是起个线程池去调用这些监听器的方法
而监听器的处理就看各个监听器的具体实现了
Spring事件监听机制的更多相关文章
- Spring 事件监听机制及原理分析
简介 在JAVA体系中,有支持实现事件监听机制,在Spring 中也专门提供了一套事件机制的接口,方便我们实现.比如我们可以实现当用户注册后,给他发送一封邮件告诉他注册成功的一些信息,比如用户订阅的主 ...
- Spring事件监听机制源码解析
Spring事件监听器使用 1.Spring事件监听体系包括三个组件:事件.事件监听器,事件广播器. 事件:定义事件类型和事件源,需要继承ApplicationEvent. package com.y ...
- SpringBoot事件监听机制及观察者模式/发布订阅模式
目录 本篇要点 什么是观察者模式? 发布订阅模式是什么? Spring事件监听机制概述 SpringBoot事件监听 定义注册事件 注解方式 @EventListener定义监听器 实现Applica ...
- Spring ApplicationContext(八)事件监听机制
Spring ApplicationContext(八)事件监听机制 本节则重点关注的是 Spring 的事件监听机制,主要是第 8 步:多播器注册:第 10 步:事件注册. public void ...
- Spring的事件监听机制
最近公司在重构广告系统,其中核心的打包功能由广告系统调用,即对apk打包的调用和打包完成之后的回调,需要提供相应的接口给广告系统.因此,为了将apk打包的核心流程和对接广告系统的业务解耦,利用了spr ...
- 7_3.springboot2.x启动配置原理_3.事件监听机制
事件监听机制配置在META-INF/spring.factories ApplicationContextInitializer SpringApplicationRunListenerioc容器中的 ...
- SpringBoot事件监听机制源码分析(上) SpringBoot源码(九)
SpringBoot中文注释项目Github地址: https://github.com/yuanmabiji/spring-boot-2.1.0.RELEASE 本篇接 SpringApplicat ...
- Halo 开源项目学习(六):事件监听机制
基本介绍 Halo 项目中,当用户或博主执行某些操作时,服务器会发布相应的事件,例如博主登录管理员后台时发布 "日志记录" 事件,用户浏览文章时发布 "访问文章" ...
- 4.JAVA之GUI编程事件监听机制
事件监听机制的特点: 1.事件源 2.事件 3.监听器 4.事件处理 事件源:就是awt包或者swing包中的那些图形用户界面组件.(如:按钮) 事件:每一个事件源都有自己特点有的对应事件和共性事件. ...
随机推荐
- 08、启动过程+at+crond+anacron
[root@li ~]# 加电--BIOS (basic input output system)--以什么设备来启动--/dev/sda -- mbr -- grub.conf --vmlinux ...
- web-天下武功唯快不破
没有武术是不可摧毁的,而最快的速度是获得长期成功的唯一途径.>>>>>> ----你必须尽可能快地做到这一点!---- <<<<<&l ...
- pikachu的xss及csrf
一.XSS 可解析的js 未经过滤 XSS见框就插 script 大小写 中间插入 <img src="" onerror="alert(11111)&q ...
- day12_7.12递归函数与算法
一.递归函数 递归函数是在函数的调用阶段直接或间接的调用自己. 于是下面就是一个简单的递归函数: def func(): print('我调我自己') func() func() 然而结果会报错,因为 ...
- python27期尚哥讲并发编程:
python27day23并发编程----------------------------------------------------------------------------------- ...
- bdd框架之lettuce
安装 执行 :lettuce (需要在特定的文件夹下) 结果指定到文件中
- Spring 中的异常处理
工作中遇到这样的同事,问他活干完吗,他说开发好了,结果测试时发现各种异常情况未处理,联调测试时各种未知错误,最后联调完成比他预期的两倍工作量还多.这样的开发如果是新人还可以原谅,如果有工作经验且出现多 ...
- 「总结」插头$dp$
集中做完了插头$dp$ 写一下题解. 一开始学的时候还是挺蒙的. 不过后来站在轮廓线$dp$的角度上来看就简单多了. 其实就是一种联通性$dp$,只不过情况比较多而已了. 本来转移方式有两种.逐行和逐 ...
- 洛谷 P1016 旅行者的预算
传送门 感觉自己连点生活常识都没有,竟然连油用过之后要减去都不知道,这种贪心模拟题都做不出来--思路在代码里,我菜死了 思路&&代码 //看题解过的..一点都没有成就感 #includ ...
- RAMOS与PE 到底哪里不一样?
RAMOS与PE 到底哪里不一样? 答:PE只是RAMOS的雏形.无论是system身份还是Administrator身份登录的PE都不能算是真正意义上的RAMOS. 号外号外,下面开始跑题..... ...