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 {@Overridepublic 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 {@Overridepublic 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】
下面首先来了解下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();// 实例化单实例非懒加载的BeanfinishBeanFactoryInitialization(beanFactory);// 此处会发布一个事件:ContextRefreshedEventfinishRefresh();} }
}
主要看下面这四个方法:
initApplicationEventMulticaster()
registerListeners()
finishBeanFactoryInitialization(beanFactory)
finishRefresh()
注意:在上面这四个方法执行之前,Spring的组件扫描工作已经结束了,但Bean实例化还没有。
此方法的作用是初始化应用事件广播器,这个广播器是干嘛的呢?说的直白点,里面存放了所有的Listener
protected void initApplicationEventMulticaster() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();// 工厂里是否包含 “applicationEventMulticaster” Beanif (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {this.applicationEventMulticaster =beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);} else {// 没有的话,Spring自己创建一个SimpleApplicationEventMulticasterthis.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);// 将自己创建的SimpleApplicationEventMulticaster放到Spring容器中,// name 为:applicationEventMulticasterbeanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);}}
}
此处是Spring自己创建了一个SimpleApplicationEventMulticaster
,放入到Spring
容器中,看断点图。
此方法里面是从Spring
容器中,拿到实现了ApplicationListener
接口的所有BeanName
,然后把它们名字添加到广播器中的this.defaultRetriever.applicationListenerBeans
中
protected void registerListeners() {// 注册静态指定的监听器&#xff0c;没有for (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}// 从Spring容器中拿到所有实现了ApplicationListener接口的类&#xff0c;此处能拿到我们添加的两个ListenerString[] listenerBeanNames &#61; getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {// 获取上面创建的ApplicationEventMulticaster广播器&#xff0c;把listenerBeanName放到广播器中的// this.defaultRetriever.applicationListenerBeans这个集合中&#xff0c;注意此处是放的是listenerBeanNamegetApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}Set<ApplicationEvent> earlyEventsToProcess &#61; this.earlyApplicationEvents;this.earlyApplicationEvents &#61; null;if (earlyEventsToProcess !&#61; null) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}
}
此方法就是实例化单例非懒加载的Bean
。这个方法就不具体介绍了&#xff0c;Spring
源码分析的其他文章中有详细介绍。这地方给个断点图吧&#xff0c;看看执行到此方法时&#xff0c;Spring
容器中有哪些Bean
。
从上面的断点图中可以看出&#xff0c;ScorpiosListener
、TestListener
两个Listener
已经被扫描到&#xff0c;但还没有被实例化&#xff0c;所以下面会进行它们的实例化操作。那么这两个Listener是怎么被保存到广播器ApplicationEventMulticaster
中的呢&#xff1f;答案是通过ApplicationListenerDetector
这个BeanPostProcessor
后置处理器。
// ApplicationListenerDetector类
public Object postProcessAfterInitialization(Object bean, String beanName) {// 判断当前的Bean是不是实现了ApplicationListener接口// 这两个ScorpiosListener、TestListener肯定是的啊// 此处的Bean已经实例化好了if (bean instanceof ApplicationListener) {Boolean flag &#61; 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 !&#61; null) {this.applicationEventMulticaster.addApplicationListener(listener);}this.applicationListeners.add(listener);
}// AbstractApplicationEventMulticaster类中方法
public void addApplicationListener(ApplicationListener<?> listener) {synchronized (this.retrievalMutex) {Object singletonTarget &#61; AopProxyUtils.getSingletonTarget(listener);if (singletonTarget instanceof ApplicationListener) {this.defaultRetriever.applicationListeners.remove(singletonTarget);}// 将listener放到广播器的属性中了&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;this.defaultRetriever.applicationListeners.add(listener);this.retrieverCache.clear();}
}
上面是Listener
实例化和最终保存在哪里的源码分析&#xff0c;下面要看一下&#xff0c;发布事件是怎么触发监听器的调用的呢&#xff1f;
在此方法中&#xff0c;Spring
发布了一个事件&#xff1a;ContextRefreshedEvent
。
protected void finishRefresh() {clearResourceCaches();initLifecycleProcessor();getLifecycleProcessor().onRefresh();// 发布事件&#xff0c;就关注这一个方法&#xff01;&#xff01;&#xff01;&#xff01;publishEvent(new ContextRefreshedEvent(this));LiveBeansView.registerApplicationContext(this);
}
下面来看一下这个publishEvent()
方法
protected void publishEvent(Object event, &#64;Nullable ResolvableType eventType) {ApplicationEvent applicationEvent;// 判断这个event是不是ApplicationEvent实例if (event instanceof ApplicationEvent) {applicationEvent &#61; (ApplicationEvent) event;} else {applicationEvent &#61; new PayloadApplicationEvent<>(this, event);if (eventType &#61;&#61; null) {eventType &#61; ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();}}if (this.earlyApplicationEvents !&#61; null) {this.earlyApplicationEvents.add(applicationEvent);} else {// 拿到广播器&#xff0c;然后调用广播器的multicastEvent()方法getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);}if (this.parent !&#61; null) {if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext) this.parent).publishEvent(event, eventType);} else {this.parent.publishEvent(event);}}
}
AbstractApplicationContext
类中的getApplicationEventMulticaster()
方法
// 此方法拿到之前创建的广播器applicationEventMulticaster
// 还记得是什么类型的嘛&#xff1f;对&#xff0c;是它&#xff1a;SimpleApplicationEventMulticaster
ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {if (this.applicationEventMulticaster &#61;&#61; null) {// 抛异常代码略}return this.applicationEventMulticaster;
}
SimpleApplicationEventMulticaster
广播器中的multicastEvent()
方法
public void multicastEvent(final ApplicationEvent event, &#64;Nullable ResolvableType eventType) {ResolvableType type &#61; (eventType !&#61; null ? eventType : resolveDefaultEventType(event));Executor executor &#61; getTaskExecutor();// 此getApplicationListeners(event, type)方法就是拿到广播器里面的所有Listenerfor (ApplicationListener<?> listener : getApplicationListeners(event, type)) {if (executor !&#61; null) {executor.execute(() -> invokeListener(listener, event));} else {// 调用监听器的方法&#xff01;&#xff01;&#xff01;&#xff01;invokeListener(listener, event);}}
}protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {ErrorHandler errorHandler &#61; getErrorHandler();if (errorHandler !&#61; null) {doInvokeListener(listener, event); } else {// 参数传入的是listener,终于开始调用了&#xff01;&#xff01;&#xff01;&#xff01;doInvokeListener(listener, event);}
}private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {// 调用Listener中仅有的onApplicationEvent()方法&#xff01;&#xff01;&#xff01;listener.onApplicationEvent(event);} catch (ClassCastException ex) {// 抛异常代码略 }
}
终于分析完了。这里是Spring
自己发布的一个Event
&#xff0c;所以会走到ScorpiosListener
、TestListener
两个监听器里面的else代码&#xff0c;打印System.out.println("ScorpiosEvent....dododododododododo")
&#xff0c;System.out.println("TestListener....tttttttttttttttttttttt")
这两行代码。
当执行到ac.publishEvent(scorpiosEvent)
这行代码发布Event
事件时&#xff0c;广播器又会去调用所有的Listener
&#xff0c;所以会有这两行代System.out.println("ScorpiosEvent ..." &#43; ((ScorpiosEvent) event).getMsg())
码的输出&#xff01;&#xff01;&#xff01;
Spring
中事件机制使用的是观察者设计模式&#xff0c;其中对应观察者的四个角色分别为&#xff1a;
事件Event&#xff1a;ApplicationEvent
是所有事件对象的父类。ApplicationEvent
继承自 JDK
中的 EventObject
&#xff0c;所有的事件都需要继承 ApplicationEvent
&#xff0c;并且通过 source
得到事件源
Spring
也为我们提供了很多内置事件&#xff0c;ContextRefreshedEvent
、ContextStartedEvent
、ContextStoppedEvent
、ContextClosedEvent
、RequestHandledEvent
。
事件监听器&#xff1a;ApplicationListener
&#xff0c;也就是观察者&#xff0c;继承自 JDK
的 EventListener
&#xff0c;该类中只有一个方法 onApplicationEvent()
&#xff0c;当监听的事件发生后该方法会被执行
事件源&#xff1a;ApplicationContext
&#xff0c;ApplicationContext
是 Spring
中的核心容器&#xff0c;在事件监听中 ApplicationContext
可以作为事件的发布者&#xff0c;也就是事件源。因为 ApplicationContext
继承自 ApplicationEventPublisher
。在 ApplicationEventPublisher
中定义了事件发布的方法&#xff1a;publishEvent(Object event)
事件管理&#xff1a;ApplicationEventMulticaster
&#xff0c;用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的&#xff0c;它的作用是把 Applicationcontext
发布的 Event
广播给它的监听器列表。 因为它里面手握所有监听器。
Spring
中的事件模型是一种简单的、粗粒度的监听模型&#xff0c;当有一个事件到达时&#xff0c;所有的监听器都会接收到&#xff0c;并且作出响应&#xff0c;如果希望只针对某些类型进行监听&#xff0c;需要在代码中进行控制。
当ApplicationContext
接收到事件后&#xff0c;事件的广播是Spring
内部给我们做的&#xff0c;其实在Spring
读包扫描之后&#xff0c;将所有实现ApplicationListener
的Bean
找出来&#xff0c;注册为容器的事件监听器。当接收到事件的 时候&#xff0c;Spring
会逐个调用事件监听器。