Spring之事件监听

ApplicationListener

ApplicationListener是Spring事件机制的一部分,与抽象类ApplicationEvent类配合来完成ApplicationContext的事件机制。

如果容器中存在ApplicationListener的Bean,当ApplicationContext调用publishEvent方法时,对应的Bean会被触发。这一过程是典型的观察者模式的实现。

源码

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event); }

ContextRefreshedEvent事件的监听

以Spring的内置事件ContextRefreshedEvent为例,当ApplicationContext被初始化或刷新时,会触发ContextRefreshedEvent事件,下面我们就实现一个ApplicationListener来监听此事件的发生。

@Component // 需对该类进行Bean的实例化
public class LearnListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// 打印容器中出事Bean的数量
System.out.println("监听器获得容器中初始化Bean数量:" + event.getApplicationContext().getBeanDefinitionCount());
}
}

事件发布

在容器创建完成后,在finishRefresh()方法中发布了一个事件——ContextRefreshedEvent

我们来具体看一下这个事件是如何发布的

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null"); // Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
} // 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) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}

派发事件:getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

这里的执行invokeListener主要是来回调listener的接口方法

以上就是spring中事件发布的流程。

事件派发器

在事件发布的过程中,有一步是获取事件的派发器,那么事件派发器是在哪里创建的呢?

实际上在容器初始化时,执行了initApplicationEventMulticaster()这个方法,来为容器初始化事件派发器。

protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//先来判断容器中有没有applicationEventMulticaster
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 = new SimpleApplicationEventMulticaster(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() + "]");
}
}
}

APPLICATION_EVENT_MULTICASTER_BEAN_NAME:

public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

监听器从哪里来

refresh()方法中执行了registerListeners()来给容器中注册监听器

protected void registerListeners() {
// 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!
//根据类型获取所有的监听器的Bean名称
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
//将监听器加入到派发器当中
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
} // Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}

@EventListener

除了实现ApplicationListener接口来完成事件监听以外,@EventListener这个注解也同样可以监听事件的发生

只需要将@EventListener标注在方法上面:

@EventListener(classes = {ApplicationEvent.class})
public void listen(ApplicationEvent applicationEvent){
System.out.println("监听到:"+applicationEvent);
}

十一、Spring之事件监听的更多相关文章

  1. Spring之事件监听(观察者模型)

    目录 Spring事件监听 一.事件监听案例 1.事件类 2.事件监听类 3.事件发布者 4.配置文件中注册 5.测试 二.Spring中事件监听分析 1. Spring中事件监听的结构 2. 核心角 ...

  2. Spring的事件监听机制

    最近公司在重构广告系统,其中核心的打包功能由广告系统调用,即对apk打包的调用和打包完成之后的回调,需要提供相应的接口给广告系统.因此,为了将apk打包的核心流程和对接广告系统的业务解耦,利用了spr ...

  3. Spring的事件监听ApplicationListener

    ApplicationListener是Spring事件机制的一部分,与抽象类ApplicationEvent类配合来完成ApplicationContext的事件机制. 如果容器中存在Applica ...

  4. Java Spring 自定义事件监听

    ApplicationContext 事件 定义一个context的起动监听事件 import org.springframework.context.ApplicationListener; imp ...

  5. Spring ApplicationContext(八)事件监听机制

    Spring ApplicationContext(八)事件监听机制 本节则重点关注的是 Spring 的事件监听机制,主要是第 8 步:多播器注册:第 10 步:事件注册. public void ...

  6. spring事件监听(eventListener)

    原理:观察者模式 spring的事件监听有三个部分组成,事件(ApplicationEvent).监听器(ApplicationListener)和事件发布操作. 事件 事件类需要继承Applicat ...

  7. java 事件监听

    事件监听实现: 三要素: 1.事件源(数据源,要处理的数据) 2.事件 (承载数据,传递信息并被监听) 3.监听器 (负责对数据的业务处理) --该开发用例采用了Spring的事件监听 1.  定义事 ...

  8. JAVA之旅(三十一)——JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件

    JAVA之旅(三十一)--JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件 有段时间没有更新JAVA了,我们今天来说一下JAVA中的图形化界面,也就是GUI ...

  9. Spring Boot学习笔记:ApplicationEvent和ApplicationEventListener事件监听

    采用事件监听的好处 以用户注册的业务逻辑为例,用户在填写完信息表单后,提交信息到后台,后台对用户信息进行处理,然后给用户返回处理结果的信息. 如上图所示,用户在注册时,后台需要处理一些系列流程,实际业 ...

随机推荐

  1. H5纯前端生成Excel表格

    H5纯前端生成Excel表格方法如下: <!DOCTYPE html> <html> <head> <title></title> < ...

  2. 愉快地使用Groovy Shell

    这是一篇有关Groovy Shell的帖子,以及它如何在日常工作中为您提供帮助(只要您是软件开发人员).无论您使用哪种编程语言或技术,都可以从Groovy Shell中受益.唯一真正的要求是您能够编写 ...

  3. mysql Hash索引和BTree索引区别

    Hash仅支持=.>.>=.<.<=.between.BTree可以支持like模糊查询 索引是帮助mysql获取数据的数据结构.最常见的索引是Btree索引和Hash索引. ...

  4. TCP协议如何保证可靠传输?

    一.TCP的可靠传输如何保证? 在TCP连接中,数据流必须以正确的顺序传送给对方.TCP的可靠性是通过顺序编号和确认(ACK)实现的.TCP在开始传送一个段时,为准备重传而首先将该段插入到发送队列中, ...

  5. 登录界面storyboard的一种布局方法

    布局思想:三个大点的背景视图宽高相等间距一定(30),左右距父视图距离一定(50),则宽度确定,水平方向位置确定 竖直方向:高度与宽度成一定比例,上边距父视图距离一定,竖直方向的位置和大小也确定了.输 ...

  6. 版本管理·玩转git(推到远程仓库)

    经过前面的练习,你在本地的仓库里管理代码已经比较熟练了,但如果是团队开发呢,如何配合起来呢? 我们可以把版本仓库放在互联网上,开发者把自己最新的版本推到线上仓库,同时,把线上仓库的最新代码拉到自己本地 ...

  7. logstash收集系统日志配置

    查看官方文档 https://www.elastic.co/guide/en/logstash/current/plugins-inputs-file.html 找个路径 /home/data/log ...

  8. javascript 生成指定范围内的随机数

    js 生成任意2个区间内的随机整数,js 生成两个数之间的随机数 function random(m,n) { return Math.floor(Math.random() * (n - m)) + ...

  9. CCNA基础学习

    OSI七层模型 由国际标准化组织ISO于1984年提出 是目前公认的计算机通信和Internet网络通信的基本结构模型 如见使用的最广泛的TCP/IP协议就是基于OSI(Open Systems In ...

  10. appium---Android app资源监控

    我们在做app测试的过程中,都会对app内存,cpu这些做一个简单的测试,今天简单的写下如何通过python监控app这些资源变化 实现原理 1.通过adb命令查看app资源内存 2.通过python ...