一 概述
Spring的事件监听主要涉及三个角色:1)事件:ApplicationEvent抽象类的继承者;
2)事件发布者:事件多播器ApplicationEventMulticaster接口的实现类,比如SimpleApplicationEventMulticaster;3)事件监听器:ApplicationListener 接口的实现类。
registerListeners方法主要将实现监听器接口(即ApplicationListener接口)的bean们注册到多播器中,即存储到applicationListenerBeans集合中。
二 内置事件监听
Spring提供了很多内置事件,这里以ContextRefreshedEvent举例说明。ContextRefreshedEvent是ApplicationEvent继承者,,当ApplicationContext被初始化或刷新时,会触发ContextRefreshedEvent事件。
2.1 事件
ContextRefreshedEvent是ApplicationEvent继承者,关系图如下所示。
ContextRefreshedEvent的源码:
public class ContextRefreshedEvent extends ApplicationContextEvent {
/**
* Create a new ContextRefreshedEvent.
* @param source the {@code ApplicationContext} that has been initialized
* or refreshed (must not be {@code null})
*/
public ContextRefreshedEvent(ApplicationContext source) {
super(source);
}
}
2.2 监听器
public class LearnListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// 打印容器中出事Bean的数量
System.out.println("监听器获得容器中初始化Bean数量:" + event.getApplicationContext().getBeanDefinitionCount());
String[] names = event.getApplicationContext().getBeanDefinitionNames();
for (String name : names){
System.out.println(name);
}
}
}
2.3 修改配置文件
在Spring的配置文件中添加监听器的配置
<bean id="learnListener" class="com.service.LearnListener"/>
2.4 启动类
public class BeanLifeCycle{
public static void main(String[] args) {
System.out.println("现在开始初始化容器");
ApplicationContext factory = new ClassPathXmlApplicationContext("beans.xml");
//触发监听器
((ClassPathXmlApplicationContext) factory).refresh();
((ClassPathXmlApplicationContext) factory).close();
}
}
2.5 日志
监听器获得容器中初始化Bean数量:4
监听器获得容器中初始化Bean数量:4
从日志上看,监听器的onApplicationEvent方法被调用了2次,因为刷新方法refresh()被调用了2次。第一次是在容器初始化中,Spring自身调用refresh()方法。第二次是在代码中手动调用refresh()方法。
三 自定义事件监听
3.1 事件
public class MyApplicationEvent extends ApplicationEvent {
//公共变量,存储消息
private Object meg;
//构造函数
public MyApplicationEvent(Object source, Object meg) {
super(source);
this.meg = meg;
System.out.println("这是MyApplicationEvent实现类构造器");
System.out.println("事件发生了改变:" + meg);
}
//获取消息
public Object getMeg() {
return meg;
}
}
3.2 监听器
public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {
//构造函数
public MyApplicationListener() {
System.out.println("这是MyApplicationListener实现类构造器");
}
@Override
public void onApplicationEvent(MyApplicationEvent event) {
System.out.println("事件监听器收到消息: " + event.getMeg());
}
}
3.3 修改配置文件
在Spring的配置文件中添加监听器的配置
<bean id="learnListener" class="com.service.MyApplicationListener"/>
3.4 启动类
public class BeanLifeCycle{
public static void main(String[] args) {
System.out.println("现在开始初始化容器");
ApplicationContext factory = new ClassPathXmlApplicationContext("beans.xml");
MyApplicationEvent myApplicationEvent = new MyApplicationEvent(factory, "Event changes!");
//发布事件
factory.publishEvent(myApplicationEvent);
System.out.println("现在开始关闭容器!");
((ClassPathXmlApplicationContext) factory).close();
}
}
3.5 日志
事件发生了改变:Event changes!
事件监听器收到消息: Event changes!
四 源码
4.1 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!
//获取实现ApplicationListener接口的监听器
//这个阶段监听器没有初始化
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
//获取事件多播器 ,并将实现ApplicationListener接口的Bean注册到applicationListenerBeans中
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
//earlyApplicationEvents是早期的事件,在Spring IOC整个生命周期中,比多播期的初始化要早出现
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
//赋值为null, help gc
this.earlyApplicationEvents = null;
/存储早期事件的集合被初始化
if (earlyEventsToProcess != null) {
//存储早期事件的集合中存在事件
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
//添加到多播器中
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
五 参考文献
1)JDK7在线文档
https://tool.oschina.net/apidocs/apidoc?api=jdk_7u4
2) JDK8在线文档
https://docs.oracle.com/javase/8/docs/api/
3)Spring Framework 5 中文文档
https://www.cntofu.com/book/95/index.html
4) Bruce Eckel. Java编程思想,第4版,2007,机械工业出版社
5)方腾飞,魏鹏,程晓明. Java并发编程的艺术,第1版,2015年,机械工业出版社
6)克雷格.沃斯. Spring实战,第5版,2020年,人民邮电出版社