深入理解Spring源码系列教程(11):事件机制详解
Spring源码学习笔记(11)——Event体系
一. 简介
Event体系是Spring提供的一种重要的机制,支持以事件——监听器的模式同步或者异步处理业务逻辑,并在一定程度上降低业务之间的耦合。
本篇主要介绍Event的使用方式及其运行原理。
一. 基于接口的开发示例
本节演示使用原生的接口实现Spring事件机制。
自定义事件:
public class SimpleEvent extends ApplicationEvent{
private String payload;
public SimpleEvent(ApplicationContext source,String payload) {
super(source);
this.payload = payload;
}
public String getPayload() {
return payload;
}
}
ApplicationEvent是Spring事件的抽象父类,可以继承ApplicationEvent实现自定义的事件。创建ApplicationEvent时需要制定事件源。
自定义事件监听器:
@Component
public class SimpleApplicationListener implements ApplicationListener<SimpleEvent>{
@Override
public void onApplicationEvent(SimpleEvent event) {
System.err.println("On SimpleEvent,payload: " + event.getPayload());
}
}
ApplicationListener是Spring事件监听器的接口,只有一个方法onApplicationEvent(),是接收到事件时的回调。可以实现ApplicationListener接口来创建自定义的监听器,并通过泛型声明指定监听哪类事件。
事件的发布:
public class AnnotationMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
applicationContext.publishEvent(new SimpleEvent(applicationContext,"test"));
}
}
通过ApplicationContext的publishEvent()方法即可发布事件。
控制台输出:
On SimpleEvent,payload: test
二. 基于注解的开发示例
自定义事件:Spring除了提供ApplicationEvent类型的事件之外,还支持任意Object类型的事件,并将其封装成PayloadApplicationEvent,因此开发任意类型的事件:
public class SimpleEvent {
private String payload;
public SimpleEvent(String payload) {
this.payload = payload;
}
public String getPayload() {
return payload;
}
}
基于注解的事件监听器:Spring提供了@EventListener注解,可以标注一个类或者一个方法作为事件监听器,并且可以指定监听的事件类型。当标注在方法上时,该方法即作为收到事件后的回调:
@Component
public class SimpleAnnotationListener {
//监听SimpleEvent事件
@EventListener(SimpleEvent.class)
public void onSimpleEvent(SimpleEvent event){
System.err.println("On SimpleEvent,payload: " + event.getPayload());
}
}
同样利用ApplicationContext的publishEvent()方法发布事件:
public class AnnotationMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
applicationContext.publishEvent(new SimpleEvent("test"));
}
}
控制台打印:
On SimpleEvent,payload: test
在演示了Spring事件机制的开发后,下面详细分析下源码。
三. ApplicationEventMulticaster的初始化
ApplicationEventMulticaster是Spring事件体系的核心组件,即事件多播器(分发器),它内部维护了事件类型和监听器的对应关系,并通过ApplicationEventMulticaster将一个事件分发到所有感兴趣的监听器上。ApplicationEventMulticaster的初始化在容器启动时完成,即AbstractApplicationContext的refresh()方法中。具体的处理为initApplicationEventMulticaster():
protected void initApplicationEventMulticaster() {
//首先在BeanFactory中查找name为applicationEventMulticaster的Bean,如果存在直接赋值返回,否则创建一个SimpleApplicationEventMulticaster实例并注册起来
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
在initApplicationEventMulticaster()方法的作用即初始化IoC容器的applicationEventMulticaster成员变量,,首先在当前BeanFactory中查找name为applicationEventMulticaster的Bean,如果存在则直接返回,否则创建SimpleApplicationEventMulticaster实例,并将其作为Singleton的Bean注册到容器中。SimpleApplicationEventMulticaster为目前ApplicationEventMulticaster的唯一实现类,其作用就是保存时间类型及其对应的监听器,并在容器中有事件发布时,将其派发给所有监听了该类型事件的监听器。
SimpleApplicationEventMulticaster的抽象父类AbstractApplicationEventMulticaster,看一下它的成员变量:
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
final Map<ListenerCacheKey, ListenerRetriever> retrieverCache =
new ConcurrentHashMap<ListenerCacheKey, ListenerRetriever>(64);
private ClassLoader beanClassLoader;
private BeanFactory beanFactory;
private Object retrievalMutex = this.defaultRetriever;
}
AbstractApplicationEventMulticaster用retrieverCache这个Map缓存了Event——>Listener的对应关系,key是ListenerCacheKey,即事件类型和事件源类型的二元组,value为ListenerRetriever,实际上就是ApplicationListener的一个Set,具体见源码:
private static class ListenerCacheKey {
private final ResolvableType eventType;
private final Class<?> sourceType;
public ListenerCacheKey(ResolvableType eventType, Class<?> sourceType) {
this.eventType = eventType;
this.sourceType = sourceType;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
ListenerCacheKey otherKey = (ListenerCacheKey) other;
return (ObjectUtils.nullSafeEquals(this.eventType, otherKey.eventType) &&
ObjectUtils.nullSafeEquals(this.sourceType, otherKey.sourceType));
}
@Override
public int hashCode() {
return (ObjectUtils.nullSafeHashCode(this.eventType) * 29 + ObjectUtils.nullSafeHashCode(this.sourceType));
}
}
private class ListenerRetriever {
public final Set<ApplicationListener<?>> applicationListeners;
public final Set<String> applicationListenerBeans;
private final boolean preFiltered;
public ListenerRetriever(boolean preFiltered) {
this.applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
this.applicationListenerBeans = new LinkedHashSet<String>();
this.preFiltered = preFiltered;
}
public Collection<ApplicationListener<?>> getApplicationListeners() {
LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>();
for (ApplicationListener<?> listener : this.applicationListeners) {
allListeners.add(listener);
}
if (!this.applicationListenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : this.applicationListenerBeans) {
try {
ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (this.preFiltered || !allListeners.contains(listener)) {
allListeners.add(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
return allListeners;
}
}
基于上述处理,ApplicationEventMulticaster维护了容器中所有的事件及其对应的监听器组,就可以方便地进行事件的发布。
四. 监听器的注册
- 基于接口的监听器的注册 如前文所说,可以通过实现ApplicationListener接口来自定义监听器,这种方式的监听器的注册是在AbstractApplicationContext的refresh()方法内部的registerListeners()方法中,见源码:
protected void registerListeners() {
//首先注册容器内部指定的一些静态ApplicationListener
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
//然后获取容器中所有ApplicationListener类型的Bean,进行自定义监听器的注册
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
//最后,对一些容器的早期事件进行发布
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
- 该方法首先处理监听器注册之前,容器内部的一些指定的静态监听器,默认情况下,在调用registerListeners()方法前,getApplicationListeners()会返回空集合。 下面,处理正常的监听器注册。扫描容器中所有实现了ApplicationListener接口的Bean,依次调用ApplicationEventMulticaster的addApplicationListenerBean()方法注册监听器:
@Override
public void addApplicationListenerBean(String listenerBeanName) {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
this.retrieverCache.clear();
}
}
- addApplicationListenerBean()方法会按照beanName保存监听器。 最后,对于容器中的一些早期事件进行发布。早期事件是指,在ApplicationEventMulticaster还未初始化完成时,就注册在容器中的一些事件,由于此时无法对其进行发布,则先将这些事件保存在earlyApplicationEvents中,待监听器注册完毕后统一进行发布。 以上,基于ApplicationListener接口定制的监听器就注册完毕了。
- 基于注解的监听器的注册 如前文所述,使用@EventListener注解也可以声明监听器。这是如何实现的呢? 看@EventListener源码:
* @see EventListenerMethodProcessor
*/
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EventListener {
}
- 我们看到文档中让我们参考EventListenerMethodProcessor类。EventListenerMethodProcessor是一个SmartInitializingSingleton接口的实现类,使用@EventListener注解声明的监听器就是通过这个类进行注册的。 SmartInitializingSingleton也是Spring提供的一个基础组件,类似于BeanPostProcessor,它可以拦截单实例Bean的创建行为,在Singleton的Bean实例化之后回调afterSingletonsInstantiated()进行实例化后处理。 我们来看EventListenerMethodProcessor的afterSingletonsInstantiated()方法:
public void afterSingletonsInstantiated() {
List<EventListenerFactory> factories = getEventListenerFactories();
String[] allBeanNames = this.applicationContext.getBeanNamesForType(Object.class);
for (String beanName : allBeanNames) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = this.applicationContext.getType(beanName);
try {
processBean(factories, beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
- 核心逻辑在processBean()方法中:
protected void processBean(List<EventListenerFactory> factories, String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType)) {
final Set<Method> annotatedMethods = new LinkedHashSet<Method>(1);
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(targetType);
for (Method method : methods) {
//扫描所有标记了@EventListener注解的方法
EventListener eventListener = AnnotationUtils.findAnnotation(method, EventListener.class);
if (eventListener == null) {
continue;
}
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, method);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener)
.init(this.applicationContext, this.evaluator);
}
//注册监听器
this.applicationContext.addApplicationListener(applicationListener);
annotatedMethods.add(method);
break;
}
}
}
if (annotatedMethods.isEmpty()) {
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType);
}
}
else {
// Non-empty set of methods
if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
beanName + "': " + annotatedMethods);
}
}
}
}
- 该方法的处理也很简单,及扫描该Singleton Bean的所有标记了@EventListener注解的方法,基于该方法创建一个ApplicationListener,并调用applicationContext.addApplicationListener()方法进行注册。
综上,所有基于ApplicationListener接口和使用@EventListener注解开发的事件监听器就都注册到了ApplicationEventMulticaster中。
五. 事件的发布
发布事件的方法在AbstractApplicationContext的publishEvent()方法中,该方法可以发布继承了ApplicationEvent类的事件,也可以发布普通的Object类型的事件。如果事件类型没有继承ApplicationEvent,则将其包装成一个PayloadApplicationEvent事件。
protected void publishEvent(Object event, ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
//如果event继承了ApplicationEvent类,则直接使用ApplicationEvent
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
//对于其他类型的事件,将其包装成PayloadApplicationEvent类型
else {
applicationEvent = new PayloadApplicationEvent<Object>(this, event);
if (eventType == null) {
eventType = ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, event.getClass());
}
}
//调用ApplicationEventMulticaster的multicastEvent()进行事件的多播
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
//如果存在父容器,也调用父容器的发布事件方法
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
对事件类型进行转换和包装后,调用ApplicationEventMulticaster的multicastEvent()进行事件的多播,该方法的实现在SimpleApplicationEventMulticaster中:
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//根据事件类型获取监听器组
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
//如果SimpleApplicationEventMulticaster的线程池executor不为空,则通过线程池异步调取监听器,否则同步执行。executor默认为空。
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
该方法首先根据事件类型获取对应的监听器组,然后遍历监听器,执行invokeListener()方法。这里有一个executor,是SimpleApplicationEventMulticaster内部的一个线程池,可以进行异步的事件处理,该线程池默认为空。
调起监听器的方法为invokeListener:
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
listener.onApplicationEvent(event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
listener.onApplicationEvent(event);
}
}
可以看到,这里回调了ApplicationListener的onApplicationEvent()方法。