前言
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()
通过从 BeanFactory
中直接找到然后注册。
和 3.0
以后支持的一些注解式配置的原理一样,@EventListener
是通过 EventListenerMethodProcessor
这个特殊的后置处理器完成注册的。
EventListenerMethodProcessor
实现的接口如下:
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor { }
其中, SmartInitializingSingleton
和 BeanFactoryPostProcessor
接口非常直观的告诉了我们它被调用的时机:
BeanFactoryPostProcessor
:在上下文初始化的时候,通过AbstractApplicationContext.invokeBeanFactoryPostProcessors
这个方法跟其他BeanFactory
的后置处理器被一起集中调用;SmartInitializingSingleton
:在这个Bean
完成初始化的时候;
接下来我们通过处理器分析注解式监听器的注册流程。
1、监听器方法处理器的注册
根据前文,我们知道容器在初始化过程中,通过 AbstarctApplicationContext.obtainFreshBeanFactory
创建新 BeanFactory
的时候,最终会一路绕到 AbstractRefreshableApplicationContext.loadBeanDefinitions
这个方法上,通过这个方法上下文会为自己的 BeanFactory
提前加载好 BeanDefinition
。
而这个抽象方法在不同的上下文会有不同的实现,但是基本都要通过不同的 BeanDefinitionReader
去完成这个过程。
支持注解式配置的上下文会用 AnnotatedBeanDefinitionReader
去读取配置的时候,会通过 AnnotationConfigBeanDefinitionParser
将配置信息解析为具体的 BeanDefinition
。而 Spring 就在这一步将默认配置的一些 Bean
的 BeanDefinition
给加上了。
实际上,不止 EventListenerMethodProcessor
,几乎所有针对 Spring 注解的后置处理器都是通过这种方式注册到 BeanFactory
的。
具体代码参见 AnnotationConfigUtils.registerAnnotationConfigProcessors
方法:
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { // 其他的一些注解处理器,比如 @Configuration,@Autowrite 之类的注解处理器... ... // 注册 EventListenerMethodProcessor if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME)); } // 注册名为“org.springframework.context.event.internalEventListenerFactory” EventListenerFactory if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME)); } return beanDefs; }
2、获取监听器工厂
当 EventListenerMethodProcessor
被作为一个 BeanFactoryPostProcessor
被调用时,它会从 BeanFactory
中收集所有实现了 EventListenerFactory
接口的 Bean
,然后记录在成员变量 eventListenerFactories
中:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { this.beanFactory = beanFactory; Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false); List<EventListenerFactory> factories = new ArrayList<>(beans.values()); AnnotationAwareOrderComparator.sort(factories); this.eventListenerFactories = factories; }
而监听器工厂这个类作用也显而易见,他用于把被注解的方法适配为监听器对象:
public interface EventListenerFactory { // 是否支持处理该方法 boolean supportsMethod(Method method); // 将bean中带有@EventListener注解的方法转为ApplicationListener ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method); }
值得一提的是,由于注册 EventListenerMethodProcessor
的时候也会默认支持一个名为 :"org.springframework.context.event.internalEventListenerFactory"
的 DefaultEventListenerFactory
,这保证至少有一个保底的监听器工厂。
EventListenerFactory
提供两个默认的实现:
-
DefaultEventListenerFactory
:默认的实现,支持处理所有被@EventListener
注解的方法,会将方法适配成类型为
ApplicationListenerMethodAdapter
的监听器; -
TransactionalEventListenerFactory
:支持 Spring 事务机制的监听器的工厂, 用于处理被@TransactionalEventListener
注解的方法,会将方法适配成类型为
ApplicationListenerMethodTransactionalAdapter
的监听器;
3、将方法适配为监听器
当 EventListenerMethodProcessor
作为一个 SmartInitializingSingleton
被调用的时候:
public void afterSingletonsInstantiated() { ConfigurableListableBeanFactory beanFactory = this.beanFactory; Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set"); // 获取工厂中的全部 Bean String[] beanNames = beanFactory.getBeanNamesForType(Object.class); for (String beanName : beanNames) { if (!ScopedProxyUtils.isScopedTarget(beanName)) { Class<?> type = null; try { // 如果是代理对象,则获取原始对象的类型 type = AutoProxyUtils.determineTargetClass(beanFactory, beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex); } } if (type != null) { // 实现了ScopedObject接口 if (ScopedObject.class.isAssignableFrom(type)) { try { // 获取原始的Bean对象 Class<?> targetClass = AutoProxyUtils.determineTargetClass( beanFactory, ScopedProxyUtils.getTargetBeanName(beanName)); if (targetClass != null) { type = targetClass; } } catch (Throwable ex) { // An invalid scoped proxy arrangement - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex); } } } try { // 处理 Bean processBean(beanName, type); } catch (Throwable ex) { throw new BeanInitializationException("Failed to process @EventListener " + "annotation on bean with name '" + beanName + "'", ex); } } } } }
抛开对代理对象的一些检验和处理,我们直接看看 processBean
方法:
private void processBean(final String beanName, final Class<?> targetType) { if (!this.nonAnnotatedClasses.contains(targetType) && // targetType类名不以“java.”开头,且不为Ordered接口 AnnotationUtils.isCandidateClass(targetType, EventListener.class) && // 是未被@Component注解的Spring内部类 !isSpringContainerClass(targetType)) { Map<Method, EventListener> annotatedMethods = null; try { // 查找直接或间接带有@EventListener注解的方法 annotatedMethods = MethodIntrospector.selectMethods(targetType, (MethodIntrospector.MetadataLookup<EventListener>) method -> AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class)); } catch (Throwable ex) { // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex); } } // 如果该类没有直接或间接带有@EventListener注解的方法,则记录并在下次查询时跳过 if (CollectionUtils.isEmpty(annotatedMethods)) { this.nonAnnotatedClasses.add(targetType); if (logger.isTraceEnabled()) { logger.trace("No @EventListener annotations found on bean class: " + targetType.getName()); } } else { // Non-empty set of methods ConfigurableApplicationContext context = this.applicationContext; Assert.state(context != null, "No ApplicationContext set"); List<EventListenerFactory> factories = this.eventListenerFactories; Assert.state(factories != null, "EventListenerFactory List not initialized"); // 遍历注解方法,并遍历监听器工厂 for (Method method : annotatedMethods.keySet()) { for (EventListenerFactory factory : factories) { // 若工厂支持处理 if (factory.supportsMethod(method)) { // 将方法包装为ApplicationListener Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName)); ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse); // 如果监听器类型为ApplicationListenerMethodAdapter,则需要传入专门的SpEL表达式解析器EventExpressionEvaluator用于支持@EventListener.condition属性 if (applicationListener instanceof ApplicationListenerMethodAdapter) { ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator); } // 将监听器加入中的 context.addApplicationListener(applicationListener); break; } } } if (logger.isDebugEnabled()) { logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" + beanName + "': " + annotatedMethods); } } } } @Override public void addApplicationListener(ApplicationListener<?> listener) { Assert.notNull(listener, "ApplicationListener must not be null"); if (this.applicationEventMulticaster != null) { this.applicationEventMulticaster.addApplicationListener(listener); } this.applicationListeners.add(listener); }
Spring 在这一步主要趁着 EventListenerMethodProcessor
在 BeanFactory
中初始化的时候干了两件事:
- 检查
BeanFactory
中的所有的Bean
,筛选出其中有成员方法直接或间接带有@EventListener
注解的Bean
; - 将此类
Bean
的方法通过EventListenerFactory
封装为ApplicationListener
对象; - 然后将这些转换后得到的
ApplicationListener
注册到上下文中的广播器中;
此外,这里有一个比较有意思的细节,就是由于 @EventListener
注解是支持在 condition
中通过 SpEL
表达式进行一些判断的,因此在这一步,针对默认的监听适配器实现 ApplicationListenerMethodAdapter
,提供了一个 init
方法用于把 SpEL
表达式解析器塞进去:
if (applicationListener instanceof ApplicationListenerMethodAdapter) { ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator); }
换而言之,如果我们希望让 @EventListener.condition
支持更多功能,就可以在这个地方动点手脚,比如向 SpEL
表达式上下文注册更多变量。
4、监听器的注册
上一节中提到,在 EventListenerMethodProcessor.processBean
将方法转换为 ApplicationListener
后会将其注入广播器:
public void addApplicationListener(ApplicationListener<?> listener) { Assert.notNull(listener, "ApplicationListener must not be null"); if (this.applicationEventMulticaster != null) { // 注册到上下文中的广播器中 this.applicationEventMulticaster.addApplicationListener(listener); } this.applicationListeners.add(listener); }
而 AbstractApplicationContext
会将该方法代理到内部持有的广播器实例的 ApplicationEventMulticaster.addApplicationListener
方法:
public void addApplicationListener(ApplicationListener<?> listener) { synchronized (this.defaultRetriever) { // Explicitly remove target for a proxy, if registered already, // in order to avoid double invocations of the same listener. Object singletonTarget = AopProxyUtils.getSingletonTarget(listener); if (singletonTarget instanceof ApplicationListener) { this.defaultRetriever.applicationListeners.remove(singletonTarget); } this.defaultRetriever.applicationListeners.add(listener); this.retrieverCache.clear(); } }
该方法最终将监听器添加到广播器持有的 DefaultListenerRetriever
对象实例中,跟已经注册到其中的编程式监听器一起,以待后续使用。
四、监听器工厂
通过上文,我们知道注解式监听器依赖监听器工厂 EventListenerFactory
将 Bean
中的注解方法转为 ApplicationListener
实例。
实际上,我们知道 spring 除了支持 @EventListener
注解外,还提供了 @TransactionalEventListener
注解,用于注册支持事务的注解式监听器,因此 EventListenerFactory
实际上也提供了两类工厂分别用于支持这两种实现:
-
DefaultEventListenerFactory
:默认的实现,支持处理所有被@EventListener
注解的方法,会将方法适配成类型为
ApplicationListenerMethodAdapter
的监听器; -
TransactionalEventListenerFactory
:支持 Spring 事务机制的监听器的工厂, 用于处理被@TransactionalEventListener
注解的方法,会将方法适配成类型为
ApplicationListenerMethodTransactionalAdapter
的监听器;
1、通用监听器工厂
通用监听器工厂的代码及其简单,它的特点如下:
- 支持处理任何方法:
supportsMethod
方法固定返回true
; - 总是最晚被执行:
getOrder
默认返回Ordered.LOWEST_PRECEDENCE
; - 总是将注解方法适配为
ApplicationListenerMethodAdapter
类型的监听器;
public class DefaultEventListenerFactory implements EventListenerFactory, Ordered { private int order = LOWEST_PRECEDENCE; public void setOrder(int order) { this.order = order; } @Override public int getOrder() { return this.order; } @Override public boolean supportsMethod(Method method) { return true; } @Override public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) { return new ApplicationListenerMethodAdapter(beanName, type, method); } }
2、事务监听器工厂
事件监听器工厂代码也并不复杂,相比 DefaultEventListenerFactory
,它的特点如下:
- 默认比
DefaultEventListenerFactory
更先被调用:getOrder
默认返回 50,比DefaultEventListenerFactory
返回的Ordered.LOWEST_PRECEDENCE
值更小; - 仅支持处理直接或间接被
@TransactionalEventListener
注解的方法; - 总是将注解方法适配为
ApplicationListenerMethodTransactionalAdapter
类型的监听器;
public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered { private int order = 50; public void setOrder(int order) { this.order = order; } @Override public int getOrder() { return this.order; } @Override public boolean supportsMethod(Method method) { return AnnotatedElementUtils.hasAnnotation(method, TransactionalEventListener.class); } @Override public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) { return new ApplicationListenerMethodTransactionalAdapter(beanName, type, method); } }
总结
当 Spring 容器启动,上下文调用 AbstractApplicationContext.refresh
方法对其进行初始化时,Spring 事件机制的两个核心组件:广播器、监听器也在该过程完成初始化。
-
在
AbstractApplicationContext.initApplicationEventMulticaster
这一步,Spring 为上下文创建并挂载了广播器ApplicationEventMulticaster
的实例; -
在
AbstractApplicationContext.registerListeners
这一步,Spring 将容器中所有实现了ApplicationListener
接口的Bean
注册到广播器中; -
而在
AbstractApplicationContext.finishBeanFactoryInitialization
这一步,Spring 会初始化容器中所有非懒加载的Bean
,此时会一并实例化EventListenerMethodProcessor
这个Bean
后置处理器:-
这个
Bean
由上下文在准备BeanFactory
时,调用loadBeanDefinitions
方法时注册到容器; -
由于
EventListenerMethodProcessor
本身实现了SmartInitializingSingleton
接口,因此实例化后会触发其回调函数,此时EventListenerMethodProcessor
会把容器中所有的Bean
都拿出来解析; -
若
Bean
中存在直接或间接被@EventListener
注解的方法,则会将其取出,并通过EventListenerFactory
将其适配为对应的ApplicationListener
实例,然后再将适配完的监听器注册到容器中; -
由于 Spring 除了
@EventListener
注解还提供了支持事务的@TransactionalEventListener
注解,因此提供了两类监听器工厂:DefaultEventListenerFactory
:默认的实现,支持处理所有被@EventListener
注解的方法;TransactionalEventListenerFactory
:支持 Spring 事务机制的监听器的工厂, 用于处理被@TransactionalEventListener
注解的方法;
-
至此,当 AbstractApplicationContext.refresh
执行完毕,即上下文初始化完成后,广播器与所有编程式或注解式监听器皆初始化完毕,并且完成了注册。