Spring源码学习笔记(11)——Event体系

时间:2022-07-24
本文章向大家介绍Spring源码学习笔记(11)——Event体系,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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维护了容器中所有的事件及其对应的监听器组,就可以方便地进行事件的发布。

四. 监听器的注册

  1. 基于接口的监听器的注册 如前文所说,可以通过实现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);
        }
    }
}
  1. 该方法首先处理监听器注册之前,容器内部的一些指定的静态监听器,默认情况下,在调用registerListeners()方法前,getApplicationListeners()会返回空集合。 下面,处理正常的监听器注册。扫描容器中所有实现了ApplicationListener接口的Bean,依次调用ApplicationEventMulticaster的addApplicationListenerBean()方法注册监听器:
@Override
public void addApplicationListenerBean(String listenerBeanName) {
    synchronized (this.retrievalMutex) {
        this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
        this.retrieverCache.clear();
    }
}
  1. addApplicationListenerBean()方法会按照beanName保存监听器。 最后,对于容器中的一些早期事件进行发布。早期事件是指,在ApplicationEventMulticaster还未初始化完成时,就注册在容器中的一些事件,由于此时无法对其进行发布,则先将这些事件保存在earlyApplicationEvents中,待监听器注册完毕后统一进行发布。 以上,基于ApplicationListener接口定制的监听器就注册完毕了。
  2. 基于注解的监听器的注册 如前文所述,使用@EventListener注解也可以声明监听器。这是如何实现的呢? 看@EventListener源码:
* @see EventListenerMethodProcessor
 */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface EventListener {
}
  1. 我们看到文档中让我们参考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);
            }
        }
    }
}
  1. 核心逻辑在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);
            }
        }
    }
}
  1. 该方法的处理也很简单,及扫描该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()方法。