Spring中ApplicationEvent事件机制源码详解
作者:止步前行
一、ApplicationEvent应用
先定义一个 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 事件机制的源码吧。
二、ApplicationEvent源码分析
Spring 的事件机制采用的是观察者设计模式
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 容器中,看断点图。
3. registerListeners()
此方法里面是从 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<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
4. finishBeanFactoryInitialization()
此方法就是实例化单例非懒加载的 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 实例化和最终保存在哪里的源码分析,下面要看一下,发布事件是怎么触发监听器的调用的呢?
5. finishRefresh()
在此方法中, 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会逐个调用事件监听器。
到此这篇关于Spring中ApplicationEvent事件机制源码详解的文章就介绍到这了,更多相关ApplicationEvent事件机制源码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
- Spring中ApplicationEventPublisher发布订阅模式的实现
- SpringBoot使用ApplicationEvent&Listener完成业务解耦
- 使用Spring的ApplicationEvent实现本地事件驱动的实现方法
- SpringBoot中ApplicationEvent和ApplicationListener用法小结
- 基于Spring Boot应用ApplicationEvent案例场景
- 详解SpringBoot实现ApplicationEvent事件的监听与发布
- 详解SpringBoot 发布ApplicationEventPublisher和监听ApplicationEvent事件