Spring 事件监听
Spring 的核心是 ApplicationContext,它负责管理 Bean的完整生命周期;当加载 Bean 时,ApplicationContext 发布某些类型的事件;例如,当上下文启动时,ContextStartedEvent 发布消息,当上下文停止时,ContextStoppedEvent 发布消息;
通过 ApplicationEvent 类和 ApplicationListener 接口来提供在 ApplicationContext 中处理事件;如果一个 Bean 实现 ApplicationListener 接口,那么每次 ApplicationEvent 被发布到 ApplicationContext 上,那个 Bean实例会被通知;类似MQ的发布订阅;
ApplicationEvent UML图如下:
Spring常用事件
序号 | Spring 事件 |
---|---|
1 | ContextRefreshedEvent:ApplicationContext 被初始化或刷新时,该事件被发布;这也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法来发生;容器刷新完成(所有bean都完全创建)会发布这个事件; |
2 | ContextStartedEvent:当使用 ConfigurableApplicationContext 接口中的 start() 方法启动 ApplicationContext 时,该事件被发布; |
3 | ContextStoppedEvent:当使用 ConfigurableApplicationContext 接口中的 stop() 方法停止 ApplicationContext 时,发布这个事件; |
4 | ContextClosedEvent:当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布; |
5 | RequestHandledEvent:在Web应用中,当一个http请求结束触发该事件; |
ApplicationContext
ApplicationContext即应用上下文,继承自BeanFactory接口,可用于获取Spring 管理的Bean对象实例;
ApplicationContextAware:Aware是属性注入,ApplicationContextAware与ApplicationContext不同的是,当Spring容器初始化的时候,实现了 ApplicationContextAware 接口的 Bean会自动注入ApplicationContext;
使用如下:
自定义ApplicationContextAware
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
private ApplicationContext applicationContext; /**
* 上下文实例
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
} /**
* 获取上下文
* @return
*/
public ApplicationContext getApplicationContext() {
return this.applicationContext;
} /**
* 通过类名获取Bean实例
* @param name
* @return
*/
public Object getBean(String name) {
return this.applicationContext.getBean(name);
} /**
* 通过字节码获取Bean实例
* @param clazz
* @param <T>
* @return
*/
public <T> T getBean(Class<T> clazz) {
return this.applicationContext.getBean(clazz);
}
}
自定义监听器
@Slf4j
@Component
public class MyListener implements ApplicationListener { @Override
public void onApplicationEvent(ApplicationEvent event) { if (event instanceof MyApplicationEvent) {
log.info("recv:" + event);
} else {
log.info("recv 容器本身:" + event);
}
}
}
自定义事件
public class MyApplicationEvent extends ApplicationEvent {
private Person person; public Person getPerson() {
return person;
} public void setPerson(Person person) {
this.person = person;
} public MyApplicationEvent(Object source, Person person) {
super(source);
this.person = person;
} /**
* Create a new ApplicationEvent.
*
* @param source the object on which the event initially occurred (never {@code null})
*/
public MyApplicationEvent(Object source) {
super(source);
}
}
在controller添加一个发布事件的方法
@Autowired
private ApplicationContextProvider provider; @GetMapping("/publish")
public String publish() {
ApplicationContext applicationContext = provider.getApplicationContext();
Person person = new Person();
person.setId(1);
person.setAddress("chn");
person.setName("test");
person.setPhone("123"); applicationContext.publishEvent(new MyApplicationEvent(person) {
});
log.info("applicationContext:{}", applicationContext); return "applicationContext: " + applicationContext;
}
当往/publish这个映射发请求的时候,publishEvent方法会发送事件;监听器就会就会接收;
ApplicationListener
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event); }
ApplicationListener
监听ApplicationEvent
及其子类的事件;
AbstractApplicationContext.java
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
...
}
ConfigurableApplicationContext:SPI接口将由大多数应用程序上下文实现;除了提供中的应用程序上下文客户端方法外,还提供了配置应用程序上下文的功能在ApplicationContext接口;
refresh方法执行容器的加载
public void refresh() throws BeansException, IllegalStateException {
...
// Initialize event multicaster for this context.
initApplicationEventMulticaster(); ...
// Last step: publish corresponding event.
finishRefresh();
... } 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.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
//没有则new "applicationEventMulticaster"的组件,并加入到容器中,注入到"applicationEventMulticaster",registerSingleton会在存储所有注册的监听器map中查找监听器是否存在,不存在则往map中执行put操作
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 + "]");
}
}
}
finshRefresh方法
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches(); // Initialize lifecycle processor for this context.
initLifecycleProcessor(); // Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh(); // Publish the final event.
publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
publishEvent方法 发布事件
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
} protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
} // 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...
// 判断当前ApplicationContext有没有父级ApplicationContext
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
AbstractApplicationEventMulticaster提供基本的监听器注册功能
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster { }
SimpleApplicationEventMulticaster.java
//将给定的应用程序事件分发到对应的监听器
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
} //调用给定事件的监听器
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
} private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
//调用实现ApplicationListener接口的onApplicationEvent方法
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
Spring 事件监听的更多相关文章
- Spring事件监听Demo
Spring事件监听实现了观察者模式.本Demo在junit4测试环境中实现 主要有三个类事件类.监听器类.事件发布类(入口) 事件类必须继承 ApplicationEvent,代码如下: impor ...
- Spring事件监听机制源码解析
Spring事件监听器使用 1.Spring事件监听体系包括三个组件:事件.事件监听器,事件广播器. 事件:定义事件类型和事件源,需要继承ApplicationEvent. package com.y ...
- spring事件监听(eventListener)
原理:观察者模式 spring的事件监听有三个部分组成,事件(ApplicationEvent).监听器(ApplicationListener)和事件发布操作. 事件 事件类需要继承Applicat ...
- Spring 事件监听机制及原理分析
简介 在JAVA体系中,有支持实现事件监听机制,在Spring 中也专门提供了一套事件机制的接口,方便我们实现.比如我们可以实现当用户注册后,给他发送一封邮件告诉他注册成功的一些信息,比如用户订阅的主 ...
- Spring事件监听机制
前言 Spring中的事件机制其实就是设计模式中的观察者模式,主要由以下角色构成: 事件 事件监听器(监听并处理事件) 事件发布者(发布事件) 首先看一下监听器和发布者的接口定义 public int ...
- Spring事件监听ApplicationListener源码流程分析
spring的事件机制是基于观察者设计模式的,ApplicationListener#onApplicationEvent(Event)方法,用于对事件的处理 .在容器初始化的时候执行注册到容器中的L ...
- Spring之事件监听(观察者模型)
目录 Spring事件监听 一.事件监听案例 1.事件类 2.事件监听类 3.事件发布者 4.配置文件中注册 5.测试 二.Spring中事件监听分析 1. Spring中事件监听的结构 2. 核心角 ...
- Spring的事件监听机制
最近公司在重构广告系统,其中核心的打包功能由广告系统调用,即对apk打包的调用和打包完成之后的回调,需要提供相应的接口给广告系统.因此,为了将apk打包的核心流程和对接广告系统的业务解耦,利用了spr ...
- SpringBoot事件监听机制及观察者模式/发布订阅模式
目录 本篇要点 什么是观察者模式? 发布订阅模式是什么? Spring事件监听机制概述 SpringBoot事件监听 定义注册事件 注解方式 @EventListener定义监听器 实现Applica ...
随机推荐
- Linux实战(19):Shell交互式read 用法
read 用法有好几种,我在实战过程中用到了 -p,记一笔以防不用忘记了. 实例 #!/bin/bash echo "检测IP是否被占用" while read -p " ...
- Redis基础知识补充及持久化、备份介绍
Redis知识补充 在上一篇博客<Redis基础认识及常用命令使用(一)–技术流ken>中已经介绍了redis的一些基础知识,以及常用命令的使用,本篇博客将补充一些基础知识以及redis持 ...
- Springboot+Vue实现仿百度搜索自动提示框匹配查询功能
案例功能效果图 前端初始页面 输入搜索信息页面 点击查询结果页面 环境介绍 前端:vue 后端:springboot jdk:1.8及以上 数据库:mysql 核心代码介绍 TypeCtrler .j ...
- ps -ef | grep使用详解
转载于: https://www.cnblogs.com/freinds/p/8074651.html ps命令将某个进程显示出来 grep命令是查找 中间的|是管道命令 是指ps命令与grep同 ...
- get请求传递json格式数据的两种方法
get请求参数为json格式数据,使用pyhton+request的两种实现方式如下: 方法一:使用requests.request() 示例代码如下: 1.导入requests和json impor ...
- 纯粹极简的react状态管理组件unstated
简介 unstated是一个极简的状态管理组件 看它的简介:State so simple, it goes without saying 对比 对比redux: 更加灵活(相对的缺点是缺少规则,需要 ...
- Spring Boot 系统启动任务定义
前言 系统任务:在项目启动阶段要做一些数据初始化操作,这些操作有一个共同的特点,只在项目启动时进行,以后都不再执行. 应用场景:例如配置文件加载,数据库初始化等操作 Spring Boot出现之前 解 ...
- tu
1 第五章 图 2 //结构定义 3 #define MaxVertexNum 100 //图中顶点数目的最大值 4 typedef struct ArcNode{ //边表节点 5 int adjv ...
- STM32之旅6——WWDG
WWDG是stm32f103的窗口看门狗,使用的时钟是APB1的时钟,在使用wwdg是被一个小问题困扰了很久--没有打开中断,无法喂狗,一直复位. 初始化完之后需要使能中断: __HAL_WWDG_E ...
- javaagent+asm破解censum
内容介绍 最近在学习字节码相关知识,了解到通过ASM字节码改写技术来做破解一些软件破解,非常感兴趣,本文记录一下破解 Censum的过程(仅个人学习使用). 之前也写过一篇暴力破解Censum的文章, ...