前言
Spring 从 3.x
开始支持事件机制。在 Spring 的事件机制中,我们可以令一个事件类继承 ApplicationEvent
类,然后将实现了 ApplicationListener
的 Bean
注册到 spring 容器,最后向 ApplicationEventPublisher
推送事件对象即可令所有订阅者收到事件。在 4.2
以后,甚至不需要实现 ApplicationListener
接口,仅需在 Bean
中方法标记 @EventListener
注解即可。
笔者将基于 Spring 源码的 5.2.x
分支,分析该功能是如何实现的。
本文是其中的第一篇文章,将分析广播器与监听的是如何被初始化,并完成注解流程的。
在开始前,推荐先阅读前文了解 Spring 容器的初始化过程与 BeanFactory
中 Bean
的创建,如果可能,还可以了解一点 Spring 的注解机制,这将更有利于流程与一些代码的理解。
一、广播器的创建
在前文,我们知道容器的初始化是通过 AbstractApplicationContext.refresh()
方法完成的,事件机制的相关组件同样也离不开容器,因此事件系统的初始化也通过该方法完成。
AbstractApplicationContext.initApplicationEventMulticaster()
是第一步,它的作用很简单:
如果当前 BeanFactory
有名为 “applicationEventMulticaster”
的 ApplicationEventMulticaster
,就把它设置为当前上下文的事件广播器,否则就创建并在 BeanFactory
中注册一个 SimpleApplicationEventMulticaster
实例作为当前上下文的事件广播器。
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); if (logger.isTraceEnabled()) { logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { // 没有就创建一个SimpleApplicationEventMulticaster作为当前上下文的事件广播器 this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); if (logger.isTraceEnabled()) { logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " + "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); } } }
二、编程式监听器的注册
在 4.2
及以前版本,监听器需要显式的实现 ApplicationListener
接口,我们管这种监听器叫做编程式监听器。
编程式监听器在 AbstractApplicationContext.registerListeners()
这个方法的调用过程中被注册到注册广播器中,这一块代码逻辑也很简单:
- 向事件广播器注册已经被注册的
BeanFactroy
中,且实现了ApplicationListener
接口的监听器; - 向事件广播器注册还没有被实例化的监听器的
BeanName
; - 发布一些早期事件;
protected void registerListeners() { // 向事件广播器注册已经被注册的上下文中的监听器 for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // 向事件广播器注册指定的监听器,不过这里只注册BeanName, // 因为有些监听器Bean是由FactoryBean生产的,而在这里FactoryBean实际上还没被生成出来 String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // 发布一些早期事件 Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (!CollectionUtils.isEmpty(earlyEventsToProcess)) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
我们需要注意的是,在这一步,虽然向广播器注册了监听器,但是实际上这只是一种关系, 真正的监听器实例不一定有被创建出来 。
不过在如果上下文中存在“早期事件”,则会触发广播,此时调用 ApplicationEventMulticaster.multicastEvent()
将会提前触发广播器中那些监听器的初始化,否则按正常情况这些将等到上下文主动初始化 BeanFactory
中全部非懒加载 Bean
的时候才会一并初始化。
三、注解式监听器的注册
在 4.2
版本以后,我们可以通过在成员方法上添加 @EventListener
或者 @TransactionalEventListener
注解的方法声明一个监听器,我们管这种监听器叫做注解式监听器。
实际上,由于注解式监听器的类上没有注解或接口作为标识,因此无法直接从 BeanFactory
中查找,所以它的注册显然不能与编程式监听器一样,在 AbstractApplicationContext.registerListeners()