说到事件监听,想到的肯定是观察者模式。但是这儿主要说下spring中的监听是怎么样的流程。

这就不得不说到spring容器的refresh方法,容器启动过程中,listener相关的主要是这个三个方法:initApplicationEventMulticaster方法初始化事件多播器,后续的事件发布都是由多播器来发布的;registerListeners注册监听器到前面初始化好的多播器上面去;

finishRefresh容器启动完成最后刷新,发布ContextRefreshedEvent事件。

1.初始化多播器:获取bean工厂对象ConfigurableListableBeanFactory,判断容器中是否有applicationEventMulticaster多播器,如果没有则创建一个一个简单事件多播器SimpleApplicationEventMulticaster并注册到容器中,后续使用

2.注册监听器到多播器上并发布早期事件:首先获取容器中已有的监听器(成品对象,从第一张图中可以看到我们自己的组件对象在registerListeners方法调用的时候 还没有初始化,是在下面的finishBeanFactoryInitialization方法中才进行初始化的),注册到多播器;然后获取bean定义中的监听器,也就是我们自己定义的监听器;同样也注册到多播器上去;最后如果有早期事件就去发布早期事件(multicastEvent方法),这些事件只能由已经实例化的监听器监听,我们自己的监听器初始化是在finishBeanFactoryInitialization方法中。

发布事件:multicastEvent方法----->invokeListener方法---->doInvokeListener方法调用监听器的onApplicationEvent

可以看到这里支持异步发送,但是从上面我们初始化简单多播器的时候,executer对象并没有赋值,因此始终是同步发布。如果我们想实现异步发布事件,那么就要让上面初始化多播器的逻辑走进第一个分支。我们可以在容器中自己继承SimpleApplicationEventMulticaster,并初始化一个线程池,然后将其注册到容器中,bean的名字必须使用“applicationEventMulticaster”,因为此时容器还没有创建真正的对象,只有这个名字的bean定义才会马上去创建对象。这样就可以实现异步发布事件了。

3.执行finishRefresh方法发布ContextRefreshedEvent事件,标志的容器已经启动完成。

监听器的流程完了,我们现在来看下使用

首先实现一个自己的监听器

package com.nijunyang.spring.listener;

        import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component; /**
* Description:
* Created by nijunyang on 2020/2/20 21:53
*/
@Component
public class MyListener implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("收到事件:" + event.toString());
}
}

新建一个自己的事件:

package com.nijunyang.spring.listener;

import org.springframework.context.ApplicationEvent;

/**
* Description:
* Created by nijunyang on 2020/2/20 22:05
*/
public class MyApplicationEvent extends ApplicationEvent {
/**
* Create a new ApplicationEvent.
*
* @param source the object on which the event initially occurred (never {@code null})
*/
public MyApplicationEvent(Object source) {
super(source);
}
}

配置类:指定要扫描的包

package com.nijunyang.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; /**
* @author: create by nijunyang
* @date:2019/10/6
*/
@Configuration
@ComponentScan(basePackages = "com.nijunyang.spring.*")
public class MainConfig {
}

测试代码:在容器创建完之后发布自己的事件。

package com.nijunyang.spring;

import com.nijunyang.spring.listener.MyApplicationEvent;
import com.nijunyang.spring.model.Student;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Application { public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
context.publishEvent(new MyApplicationEvent("想涨工资"));
} }

执行代码会发现我们的监听器会监听到两个事件,因为我们监听器监听的事件是ApplicationEvent,上面说到容器启动的时候,最后会执行finishRefresh方法发布ContextRefreshedEvent事件,容器启动完成之后,我们自己手动发布了一个我们自己的事件,因此会监听到两个事件。

修改我们的监听器,只监听我们自己的事件:

package com.nijunyang.spring.listener;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component; /**
* Description:
* Created by nijunyang on 2020/2/20 21:53
*/
@Component
public class MyListener implements ApplicationListener<MyApplicationEvent> {
@Override
public void onApplicationEvent(MyApplicationEvent event) {
System.out.println("收到事件:" + event.toString());
}
}

再次执行代码,发现现在就只能监听我们自己的事件了

通过spring的监听器,我们不仅可以实现自己相关的业务,还可以通过这个机制将我们自己的组件和spring进行整合,比如阿里的nacos就是通过ApplicationListener与spring整合的;

springboot和spring中的一些事件:

ContextClosedEvent:容器关闭的时候,我们可以监听这个事件在容器关闭的时候去清理一些缓存(比如redis)的数据

ApplicationFailedEvent:该事件为spring boot启动失败时的操作

ApplicationPreparedEvent:上下文context准备时触发

ApplicationReadyEvent:上下文已经准备完毕的时候触发,做权限认证的时候。在这个时候就可以去初始化一些权限数据。或者预备其他数据

ApplicationEnvironmentPreparedEvent:环境事先准备

Spring监听器---ApplicationListener的更多相关文章

  1. spring boot 之监听器ApplicationListener

    监听器ApplicationListener 就是spring的监听器,能够用来监听事件,典型的观察者模式.ApplicationListener和ContextRefreshedEvent一般都是成 ...

  2. Spring中ApplicationListener的使用

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

  3. Spring透过ApplicationListener来触发contextrefreshedevent事件

    Spring通过ApplicationListener接口来触发contextrefreshedevent事件在开发时有时候需要在整个应用开始运行时执行一些特定代码,比如初始化环境,准备测试数据.加载 ...

  4. 【spring】ApplicationListener传递参数到页面(解决静态+动态资源路径+静态文件的缓存控制)

    一.相对路径还是绝对路径的问题 前端页面加载资源或者请求的时候到底是使用相对路径还是绝对路径,想必大家都很清楚,用的是当然是相对路径,因为这样增加了项目的灵活性,不需要经常的改动.那既然是相对路径就需 ...

  5. SSH项目web.xml文件的常用配置【struts2的过滤器、spring监听器、解决Hibernate延迟加载问题的过滤器、解决中文乱码的过滤器】

    配置web.xml(struts2的过滤器.spring监听器.解决Hibernate延迟加载问题的过滤器.解决中文乱码的过滤器) <!-- 解决中文乱码问题 --> <filter ...

  6. SpringBoot2.0 监听器ApplicationListener的使用-监听ApplicationReadyEvent事件

    参考:http://www.shareniu.com/article/73.htm 一.需求是想将我的写一个方法能在项目启动后就运行,之前使用了redis的消息监听器,感觉可以照着监听器这个思路做,于 ...

  7. spring监听器

    1,web.xml中配,因为tomcat启动web项目时先加载web.xml. 2,spring需要启动IOC容器才能为其他框架提供服务,spring是通过监听器来启动容器,初始化 这边启动它,也得告 ...

  8. Spring监听器配置

    使用spring框架时如果同时使用org.springframework.web.util.Log4jConfigListener监听器,那么在web.xml中的监听器的注册顺序为org.spring ...

  9. [转]spring 监听器 IntrospectorCleanupListener简介

    "在服务器运行过程中,Spring不停的运行的计划任务和OpenSessionInViewFilter,使得Tomcat反复加载对象而产生框架并用时可能产生的内存泄漏,则使用Introspe ...

随机推荐

  1. EntityFramework Core一劳永逸动态加载模型,我们要知道些什么呢?

    前言 这篇文章源于一位问我的童鞋:在EntityFramework Core中如何动态加载模型呢?在学习EntityFramwork时关于这个问题已有对应园友给出答案,故没有过多研究,虽然最后解决了这 ...

  2. 【转】Java集合框架面试问题集锦

    Java集合框架(例如基本的数据结构)里包含了最常见的Java常见面试问题.很好地理解集合框架,可以帮助你理解和利用Java的一些高级特性.下面是面试Java核心技术的一些很实用的问题. Q:最常见的 ...

  3. git版本管理工具(二)

    1.查看历史版本 ·git log ·git reflog 2.版本回退 ·git reset --hard HEAD^(HEAD代表当前版本) ·HEAD^代表回退到上一个版本 以此类推 ·HEAD ...

  4. Scala实践13

    1.隐式参数 方法可以具有隐式参数列表,由参数列表开头的implicit关键字标记.如果该参数列表中的参数没有像往常一样传递,Scala将查看它是否可以获得正确类型的隐式值,如果可以,则自动传递. S ...

  5. Could not find iPhone 6 simulator

    最近原来的老项目有点问题需要处理一下,运行启动命令,就报了如下错误,提示找不到iPhone 6 模拟器. react-native run-ios Owaiss-Mac:pdm owaisahmed$ ...

  6. Python使用requests爬取一个网页并保存

    #导入 requests模块import requests #设置请求头,让网站监测是浏览器 headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 6. ...

  7. SliverAppBar 介绍及使用

    SliverAppBar控件可以实现页面头部区域展开.折叠的效果,类似于Android中的CollapsingToolbarLayout.先看下SliverAppBar实现的效果,效果图如下: Sli ...

  8. python 进程Queue

    1.作用:进程之间的数据交互 2.常用方法 """ 对象.put() 作用:放入队列一个数据 对象.get() 作用:取队列一个数据,若队列没有值,则阻塞 对象.empt ...

  9. [bzoj4417] [洛谷P3990] [Shoi2013] 超级跳马

    Description 现有一个n行m列的棋盘,一只马欲从棋盘的左上角跳到右下角.每一步它向右跳奇数列,且跳到本行或相邻行.跳越期间,马不能离开棋盘.例如,当n = 3, m = 10时,下图是一种可 ...

  10. 「 深入浅出 」集合List

    第一篇文章 「 深入浅出 」java集合Collection和Map 主要讲了对集合的整体介绍,本篇文章主要讲List相对于Collection新增的一些重要功能以及其重要子类ArrayList.Li ...