- 一、ApplicationEvent应用
- 二、ApplicationEvent源码分析
- 1. Listener监听器的注册过程
- 2. initApplicationEventMulticaster()
- 3. registerListeners()
- 4. finishBeanFactoryInitialization()
- 5. finishRefresh()
- 三、 小结
Spring
中与事件有关的接口和类主要包括ApplicationEvent
、ApplicationListener
。
下面来看一下Spring
中事件的具体应用。
先定义一个Event
:ScorpiosEvent
,继承ApplicationEvent
。
public class ScorpiosEvent extends ApplicationEvent {
private String msg;
public ScorpiosEvent(Object source,String message) {
super(source);
this.msg = message;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
定义两个Listener
:ScorpiosListener
、TestListener
。要加上@Componen
t注解,让Spring
容器管理。
// ScorpiosListener
@Component
public class ScorpiosListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof ScorpiosEvent){
System.out.println("ScorpiosEvent ..." + ((ScorpiosEvent) event).getMsg());
}else{
System.out.println("ScorpiosEvent....dododododododododo");
}
}
}
// TestListener
@Component
public class TestListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof ScorpiosEvent){
System.out.println("TestListener ..." + ((ScorpiosEvent) event).getMsg());
}else{
System.out.println("TestListener....tttttttttttttttttttttt");
}
}
}
入口函数
public static void main( String[] args )
{
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
ScorpiosEvent scorpiosEvent = new ScorpiosEvent("scorpios","aaaaaaaaaa");
ac.publishEvent(scorpiosEvent);
}
上面就是Event
的具体的一个应用,Listener
要被Spring
容器管理。
从上面的代码调用和日志可以看到,只要调用一个发布事件ac.publishEvent(scorpiosEvent)
,所有的Listener
都会被调用。注意,是所有的Listener,后面源码分析。
从上面的输出日志中可以看出,ScorpiosListener
、TestListener
监听器都被调用了两次,可代码里,明明就调用了一次啊,为什么System.out.println("ScorpiosEvent....dododododododododo")
这行代码也会被输出呢?这是为什么呢?下面就来分析下Spring
事件机制的源码吧。
Spring
的事件机制采用的是观察者设计模式,对于观察者设计模式,可以看下面这篇文章。
https://blog.csdn.net/zxd1435513775/article/details/88544924
Java设计模式——观察者模式【Observer Pattern】
1. Listener监听器的注册过程下面首先来了解下Listener
监听器是何时被添加到Spring
容器中的,Listener
被扫描后具体是存放在哪里的?下面先看一下Spring
中大名鼎鼎的refresh()
方法,如果对这个方法不了解,可以看下我对Spring
源码解析的其他文章。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备工作,包括设置启动时间,是否激活标识位,初始化属性源(property source)配置
prepareRefresh();
// 返回一个factory 为什么需要返回一个工厂? 因为要对工厂进行初始化
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备工厂
prepareBeanFactory(beanFactory);
try {
// 这个方法在当前版本的spring是没用任何代码的,可能spring期待在后面的版本中去扩展吧
postProcessBeanFactory(beanFactory);
// 调用BeanFactoryPostProcessors的后置处理器
// 在Spring环境中去执行已经被注册的FactoryProcessors
// 设置执行自定义的ProcessorBeanFactory和Spring内部自己定义的
invokeBeanFactoryPostProcessors(beanFactory);
//-------------------到此spring工厂完成创建工作--------------------------
// 注册BeanPostProcessor后置处理器
registerBeanPostProcessors(beanFactory);
initMessageSource();
// 初始化应用事件广播器
initApplicationEventMulticaster();
onRefresh();
// 注册监听器
registerListeners();
// 实例化单实例非懒加载的Bean
finishBeanFactoryInitialization(beanFactory);
// 此处会发布一个事件:ContextRefreshedEvent
finishRefresh();
}
}
}
主要看下面这四个方法:
initApplicationEventMulticaster()
registerListeners()
finishBeanFactoryInitialization(beanFactory)
finishRefresh()
注意:在上面这四个方法执行之前,Spring的组件扫描工作已经结束了,但Bean实例化还没有。
2. initApplicationEventMulticaster()此方法的作用是初始化应用事件广播器,这个广播器是干嘛的呢?说的直白点,里面存放了所有的Listener
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 工厂里是否包含 “applicationEventMulticaster” Bean
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
} else {
// 没有的话,Spring自己创建一个SimpleApplicationEventMulticaster
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
// 将自己创建的SimpleApplicationEventMulticaster放到Spring容器中,
// name 为:applicationEventMulticaster
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
}
此处是Spring自己创建了一个SimpleApplicationEventMulticaster
,放入到Spring
容器中,看断点图。
此方法里面是从Spring
容器中,拿到实现了ApplicationListener
接口的所有BeanName
,然后把它们名字添加到广播器中的this.defaultRetriever.applicationListenerBeans
中
protected void registerListeners() {
// 注册静态指定的监听器,没有
for (ApplicationListener listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 从Spring容器中拿到所有实现了ApplicationListener接口的类,此处能拿到我们添加的两个Listener
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
// 获取上面创建的ApplicationEventMulticaster广播器,把listenerBeanName放到广播器中的
// this.defaultRetriever.applicationListenerBeans这个集合中,注意此处是放的是listenerBeanName
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
Set earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
此方法就是实例化单例非懒加载的Bean
。这个方法就不具体介绍了,Spring
源码分析的其他文章中有详细介绍。这地方给个断点图吧,看看执行到此方法时,Spring
容器中有哪些Bean
。
从上面的断点图中可以看出,ScorpiosListener
、TestListener
两个Listener
已经被扫描到,但还没有被实例化,所以下面会进行它们的实例化操作。那么这两个Listener是怎么被保存到广播器ApplicationEventMulticaster
中的呢?答案是通过ApplicationListenerDetector
这个BeanPostProcessor
后置处理器。
// ApplicationListenerDetector类
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 判断当前的Bean是不是实现了ApplicationListener接口
// 这两个ScorpiosListener、TestListener肯定是的啊
// 此处的Bean已经实例化好了
if (bean instanceof ApplicationListener) {
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// 将这个实现了ApplicationListener接口的Bean放到广播器的
// this.defaultRetriever.applicationListeners属性中
this.applicationContext.addApplicationListener((ApplicationListener) bean);
} else if (Boolean.FALSE.equals(flag)) {
this.singletonNames.remove(beanName);
}
}
return bean;
}
// AbstractApplicationContext类中方法
public void addApplicationListener(ApplicationListener listener) {
if (this.applicationEventMulticaster != null) {
this.applicationEventMulticaster.addApplicationListener(listener);
}
this.applicationListeners.add(listener);
}
// AbstractApplicationEventMulticaster类中方法
public void addApplicationListener(ApplicationListener listener) {
synchronized (this.retrievalMutex) {
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
// 将listener放到广播器的属性中了!!!!!
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
上面是Listener
实例化和最终保存在哪里的源码分析,下面要看一下,发布事件是怎么触发监听器的调用的呢?
在此方法中,Spring
发布了一个事件:ContextRefreshedEvent
。
protected void finishRefresh() {
clearResourceCaches();
initLifecycleProcessor();
getLifecycleProcessor().onRefresh();
// 发布事件,就关注这一个方法!!!!
publishEvent(new ContextRefreshedEvent(this));
LiveBeansView.registerApplicationContext(this);
}
下面来看一下这个publishEvent()
方法
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
ApplicationEvent applicationEvent;
// 判断这个event是不是ApplicationEvent实例
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
} else {
applicationEvent = new PayloadApplicationEvent(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
}
}
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
// 拿到广播器,然后调用广播器的multicastEvent()方法
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
} else {
this.parent.publishEvent(event);
}
}
}
AbstractApplicationContext
类中的getApplicationEventMulticaster()
方法
// 此方法拿到之前创建的广播器applicationEventMulticaster
// 还记得是什么类型的嘛?对,是它:SimpleApplicationEventMulticaster
ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
if (this.applicationEventMulticaster == null) {
// 抛异常代码略
}
return this.applicationEventMulticaster;
}
SimpleApplicationEventMulticaster
广播器中的multicastEvent()
方法
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
// 此getApplicationListeners(event, type)方法就是拿到广播器里面的所有Listener
for (ApplicationListener listener : getApplicationListeners(event, type)) {
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) {
doInvokeListener(listener, event);
} else {
// 参数传入的是listener,终于开始调用了!!!!
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 调用Listener中仅有的onApplicationEvent()方法!!!
listener.onApplicationEvent(event);
} catch (ClassCastException ex) {
// 抛异常代码略
}
}
终于分析完了。这里是Spring
自己发布的一个Event
,所以会走到ScorpiosListener
、TestListener
两个监听器里面的else代码,打印System.out.println("ScorpiosEvent....dododododododododo")
,System.out.println("TestListener....tttttttttttttttttttttt")
这两行代码。
当执行到ac.publishEvent(scorpiosEvent)
这行代码发布Event
事件时,广播器又会去调用所有的Listener
,所以会有这两行代System.out.println("ScorpiosEvent ..." + ((ScorpiosEvent) event).getMsg())
码的输出!!!
Spring
中事件机制使用的是观察者设计模式,其中对应观察者的四个角色分别为:
-
事件Event:
ApplicationEvent
是所有事件对象的父类。ApplicationEvent
继承自JDK
中的EventObject
,所有的事件都需要继承ApplicationEvent
,并且通过source
得到事件源Spring
也为我们提供了很多内置事件,ContextRefreshedEvent
、ContextStartedEvent
、ContextStoppedEvent
、ContextClosedEvent
、RequestHandledEvent
。 -
事件监听器:
ApplicationListener
,也就是观察者,继承自JDK
的EventListener
,该类中只有一个方法onApplicationEvent()
,当监听的事件发生后该方法会被执行 -
事件源:
ApplicationContext
,ApplicationContext
是Spring
中的核心容器,在事件监听中ApplicationContext
可以作为事件的发布者,也就是事件源。因为ApplicationContext
继承自ApplicationEventPublisher
。在ApplicationEventPublisher
中定义了事件发布的方法:publishEvent(Object event)
-
事件管理:
ApplicationEventMulticaster
,用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把Applicationcontext
发布的Event
广播给它的监听器列表。 因为它里面手握所有监听器。
Spring
中的事件模型是一种简单的、粗粒度的监听模型,当有一个事件到达时,所有的监听器都会接收到,并且作出响应,如果希望只针对某些类型进行监听,需要在代码中进行控制。
当ApplicationContext
接收到事件后,事件的广播是Spring
内部给我们做的,其实在Spring
读包扫描之后,将所有实现ApplicationListener
的Bean
找出来,注册为容器的事件监听器。当接收到事件的 时候,Spring
会逐个调用事件监听器。