【Spring框架】Spring监听器的源码分析

目录

一、Spring监听器模型

二、源码分析

2.1 initApplicationEventMulticaster():事件广播器的初始化

2.1.1 Spring默认的事件广播器SimpleApplicationEventMulticaste

2.2 registerListeners():注册事件监听器

2.3 finishRefresh():完成refresh后发布相应的内置事件

2.3.1 publishEvent(ApplicationEvent)方法:用于发布事件

2.3.1.1 multicastEvent()方法

2.3.1.1.1 getApplicationListeners(event,type)方法:获取所有监听event事件的监听器

2.3.1.1.1.1 retrieveApplicationListeners()

2.3.1.1.1.1.1 supportsEvent(listener,eventType) :判断当前监听器是否用来监听该事件

2.3.1.1.2 invokeListener()方法:执行监听器的监听逻辑

三、同步与异步

3.1 默认同步通知

3.2 异步通知设置

3.2.1 第一种,直接自定义一个多播器,然后注册到容器中顶替掉Spring自动创建的多播器

3.2.2 第二种,为现成的多播器设置设置一个线程池

3.2.3 第三种,在监听器方法上加@Async注解


一、Spring监听器模型

前面我们讲了观察者模式的模型,它的模型主要是由观察者实体和主题实体构成,而Spring的监听器模式则结合了Spring本身的特征,也就是容器化。在Spring中,监听器实体全部放在ApplicationContext中,事件也是通过ApplicationContext来进行发布(ApplicationContext就相当于一个事件发布器),具体模型如下:

我们不难看到,虽说是通过ApplicationContext发布的事件,但其并不是ApplicationContext自己进行事件的发布,而是引入了一个处理器—— EventMulticaster,直译就是事件多播器,用它来进行事件发布,它负责在大量的监听器中,针对每一个要广播的事件,找到事件对应的监听器,然后调用该监听器的响应方法,图中就是调用了监听器1、3、6。

PS: 只有在某类事件第一次广播时,EventMulticaster才会去做遍历所有监听器的事,当它针对该类事件广播过一次后,就会把对应监听器保存起来了,最后会形成一个缓存Map,下一次就能直接找到这些监听器

// 缓存
final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);

二、源码分析

在实际的面试过程中,关于Spring监听器的内容问的很少,一般只需要答出来下面的四个点即可,不用太深入的扣源码细节,明白它的设计思路就可以。

Spring在ApplicationContext接口的抽象实现类AbstractApplicationContext中完成了事件体系的搭建。

AbstractApplicationContext拥有一个applicationEventMulticaster成员变量,applicationEventMulticaster提供了容器监听器的注册表。

当Spring容器启动的时候会调用refresh初始化容器,AbstractApplicationContext在refresh()这个容器启动方法中搭建了事件的基础设施。其中AbstractApplicationContext的refresh方法实现如下:

AbstractApplicationContext.java

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();
        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);
        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            // 事件多播器的初始化
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // Check for listener beans and register them.
            // 将监听器注册到事件多播器中
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            // 完成Spring容器的refresh后,会发布Spring的一些内置事件
            finishRefresh();
        }
        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
            }
            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();
            // Reset 'active' flag.
            cancelRefresh(ex);
            // Propagate exception to caller.
            throw ex;
        }
        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

其中和监听器相关的方法就是initApplicationEventMulticaster()、registerListeners()和finishRefresh()

2.1 initApplicationEventMulticaster():事件广播器的初始化

AbstractApplicationContext.java

protected void initApplicationEventMulticaster() {x
    // 获取ConfigurableListableBeanFactory工厂
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // 首先看spring容器中是不是已经有名字为applicationEventMulticaster的对象,
    // 如果有就使用容器中已有的对象并赋值给AbstractApplicationContext类的成员属性applicationEventMulticaster 
    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对象,并赋值给applicationEventMulticaster成员属性
        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() + "]");
        }
    }
}

用户可以在配置文件中为容器定义一个自定义的事件广播器,只要实现ApplicationEventMulticaster就可以了,Spring会通过反射的机制将其注册成容器的事件广播器,如果没有找到配置的外部事件广播器, Spring默认使用 SimpleApplicationEventMulticaster作为事件广播器。

上面代码的逻辑最要是判断容器中是否有名字叫applicationEventMulticaster的事件广播器,如果有则使用已有的(这也算是Spring的一个扩展点,也就是如果我们创建了个名字是applicationEventMulticaster的事件广播器,那么就会使用我们自定义的),如果没有则新建默认的事件广播器SimpleApplicationEventMulticaster。这里会赋值给AbstractApplicationContext的applicationEventMulticaster成员变量。AbstractApplicationContext有一个名为parent的成员属性,是ApplicationContext类型,ApplicationContext也实现了ApplicationEventPublisher接口,所以它拥有事件相关的所有方法,但ApplicationContext只是一个代理,当我们调用applicationContext.publishEvent方法时,其实调用的就是applicationEventMulticaster 这个成员变量对象

2.1.1 Spring默认的事件广播器SimpleApplicationEventMulticaste

/**
 * SimpleApplicationEventMulticaster是Spring中的事件广播器类。
 * 它实现了事件的多播,即将事件通知给所有注册的监听器。
 * 这个类继承自AbstractApplicationEventMulticaster。
 */
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
    /**
     * 事件多播器可以绑定线程池,以实现发布事件和执行监听器逻辑的异步执行
     *
    @Nullable
    private Executor taskExecutor;

    @Nullable
    private ErrorHandler errorHandler;

    /**
     * 创建一个新的SimpleApplicationEventMulticaster实例。
     */
    public SimpleApplicationEventMulticaster() {
    }

    /**
     * 使用给定的BeanFactory创建一个新的SimpleApplicationEventMulticaster实例。
     * @param beanFactory 给定的BeanFactory
     */
    public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
        setBeanFactory(beanFactory);
    }

    /**
     * 设置任务执行器,用于异步执行监听器的事件处理。
     * @param taskExecutor 任务执行器
     */
    public void setTaskExecutor(@Nullable Executor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }

    /**
     * 获取当前的任务执行器。
     * @return 当前的任务执行器
     */
    @Nullable
    protected Executor getTaskExecutor() {
        return this.taskExecutor;
    }

    /**
     * 设置错误处理器,用于处理监听器抛出的异常。
     * @param errorHandler 错误处理器
     */
    public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
        this.errorHandler = errorHandler;
    }

    /**
     * 获取当前的错误处理器。
     * @return 当前的错误处理器
     */
    @Nullable
    protected ErrorHandler getErrorHandler() {
        return this.errorHandler;
    }

    /**
     * 广播给定的应用事件到所有适当的监听器。
     * @param event 要广播的应用事件
     */
    @Override
    public void multicastEvent(ApplicationEvent event) {
        multicastEvent(event, resolveDefaultEventType(event));
    }

    /**
     * 广播给定的应用事件到所有适当的监听器,可以指定事件的类型。
     * @param event 要广播的应用事件
     * @param eventType 事件的类型,如果为null,则根据事件实例自动确定类型
     */
    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        Executor executor = getTaskExecutor();
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            if (executor != null) {
                // 如果有任务执行器,使用任务执行器异步执行监听器的事件处理方法
                executor.execute(() -> invokeListener(listener, event));
            } else {
                // 否则同步执行监听器的事件处理方法
                invokeListener(listener, event);
            }
        }
    }

    /**
     * 解析默认的事件类型。
     * @param event 应用事件
     * @return 事件类型
     */
    private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
        return ResolvableType.forInstance(event);
    }

    /**
     * 调用给定的监听器处理给定的事件。
     * @param listener 要调用的应用监听器
     * @param event 当前的事件
     * @since 4.1
     */
    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = getErrorHandler();
        if (errorHandler != null) {
            try {
                // 调用监听器的事件处理方法,如果发生异常,交给错误处理器处理
                doInvokeListener(listener, event);
            } catch (Throwable err) {
                errorHandler.handleError(err);
            }
        } else {
            // 调用监听器的事件处理方法
            doInvokeListener(listener, event);
        }
    }

    /**
     * 调用监听器的事件处理方法,处理事件监听器可能抛出的异常。
     * @param listener 要调用的应用监听器
     * @param event 当前的事件
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            // 调用监听器的事件处理方法
            listener.onApplicationEvent(event);
        } catch (ClassCastException ex) {
            // 处理ClassCastException异常,可能是Lambda表达式定义的监听器,无法解析泛型事件类型
            String msg = ex.getMessage();
            if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
                // 忽略异常,记录调试日志
                Log logger = LogFactory.getLog(getClass());
                if (logger.isTraceEnabled()) {
                    logger.trace("Non-matching event type for listener: " + listener, ex);
                }
            } else {
                // 抛出其他类型的ClassCastException异常
                throw ex;
            }
        }
    }

    /**
     * 判断ClassCastException异常的消息是否匹配给定的事件类。
     * @param classCastMessage ClassCastException异常的消息
     * @param eventClass 事件的类
     * @return 如果消息匹配事件类,返回true,否则返回false
     */
    private boolean matchesClassCastMessage(String classCastMessage, Class<?> eventClass) {
        // 在Java 8中,消息以类名开头:"java.lang.String cannot be cast..."
        if (classCastMessage.startsWith(eventClass.getName())) {
            return true;
        }
        // 在Java 11中,消息以"class ..."开头,即Class.toString()的返回值
        if (classCastMessage.startsWith(eventClass.toString())) {
            return true;
        }
        // 在Java 9中,消息包含模块名:"java.base/java.lang.String cannot be cast..."
        int moduleSeparatorIndex = classCastMessage.indexOf('/');
        if (moduleSeparatorIndex != -1 && classCastMessage.startsWith(eventClass.getName(), moduleSeparatorIndex + 1)) {
            return true;
        }
        // 假设是不相关的ClassCastException异常,返回false
        return false;
    }
}

遍历注册的每个监听器,并启动来调用每个监听器的onApplicationEvent方法。由于 SimpleApplicationEventMulticaster的taskExecutor的实现类是SyncTaskExecutor,因此,该事件监听器对事件的处理是同步进行的。

2.2 registerListeners():注册事件监听器

通过registerListeners()方法将事件监听器注册到事件多播器中。在上一步事件多播器已经创建出来了,而事件监听器此时也已经在Spring容器中了,具体是什么时候创建的事件监听器我们后面会讲到。

AbstractApplicationContext.java

protected void registerListeners() {
    // Register statically specified listeners first.
    // 获取容器中所有的监听器对象
    // 这个时候正常流程是不会有监听器的,除非手动调用addApplicationListeners()
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        // 把监听器挨个的注册到我们的多播器上去
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // 这里是为了防止懒加载监听器漏网,因为懒加载的Bean只有在调用的时候才会创建,所以容器中不会用这个Bean,只能从Bean定义中去获取
    // 获取bean定义中的监听器对象    接口方式实现的监听就是在这里注册到多播器里面的
    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    // 把监听器的名称注册到我们的事件多播器上
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // 在这里获取早期事件
    // Publish early application events now that we finally have a multicaster...
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    // 在这里赋null。 也就是在此之后都就没有早期事件了
    this.earlyApplicationEvents = null;
    if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
        // 通过多播器进行播发早期事件
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

Spring根据反射机制,使用ListableBeanFactory的getBeansOfType方法,从BeanDefinitionRegistry中找出所有实现 org.springframework.context.ApplicationListener的Bean,将它们注册为容器的事件监听器,实际的操作就是将其添加到事件广播器所提供的监听器注册表中。

2.3 finishRefresh():完成refresh后发布相应的内置事件

AbstractApplicationContext.java

protected void finishRefresh() {
    // Clear context-level resource caches (such as ASM metadata from scanning).
    clearResourceCaches();

    // Initialize lifecycle processor for this context.
    initLifecycleProcessor();

    // Propagate refresh to lifecycle processor first.
    getLifecycleProcessor().onRefresh();

    // Publish the final event.
    // 发布容器启动完毕事件ContextRefreshedEvent
    publishEvent(new ContextRefreshedEvent(this));

    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}

2.3.1 publishEvent(ApplicationEvent)方法:用于发布事件

事件发布的关键方法流程如下:

org.springframework.context.support.AbstractApplicationContext#publishEvent   //发布事件
  -->org.springframework.context.support.AbstractApplicationContext#publishEvent  //发布事件
      -->org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent  //发布事件
        -->org.springframework.context.event.AbstractApplicationEventMulticaster#getApplicationListeners //找到感兴趣的事件
          -->org.springframework.context.event.AbstractApplicationEventMulticaster#retrieveApplicationListeners//找到感兴趣的事件
            -->org.springframework.context.event.AbstractApplicationEventMulticaster#supportsEvent //判断是否是感兴趣的事件

我们先跟着 finishRefresh()方法进入publishEvent(ApplicationEvent )方法,这个方法就是用于发布事件的(传入方法的就是要发布的事件),源码如下:

AbstractApplicationContext.java

public void publishEvent(ApplicationEvent event) {
    publishEvent(event, null);
}

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");
    // Decorate event as an ApplicationEvent if necessary
    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent) event;
    }
    else {
        applicationEvent = new PayloadApplicationEvent<>(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
        }
    }
    // Multicast right now if possible - or lazily once the multicaster is initialized
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }

    // Publish event via parent context as well...
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
        }
        else {
            this.parent.publishEvent(event);
        }
    }
}

在AbstractApplicationContext的publishEvent方法中, Spring委托ApplicationEventMulticaster将事件通知给所有的事件监听器。

2.3.1.1 multicastEvent()方法

所有的真正发布动作都是由multicastEvent()完成的。multicastEvent 方法很简单,调用getApplicationListeners方法找到所有对当前事件感兴趣的监听器,如果存在线程池,则异步执行监听逻辑,否则就同步执行。默认情况下执行事件的逻辑是跟发布事件是同一个线程。

SimpleApplicationEventMulticaster.java

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    // 获取当前事件多播器的线程池。事件多播器类中有一个线程池成员属性,用来记录和事件多播器绑定在一起的线程池
    Executor executor = getTaskExecutor();
    // getApplicationListeners 方法找到所有的对当前事件感兴趣的监听器
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            // 如果有配置线程池,则使用线程池执行监听逻辑,也就是触发监听器对事件发生后的执行逻辑
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            // 没有线程池,就用发布事件的线程去执行监控器在事件发生后触发的逻辑
            invokeListener(listener, event);
        }
    }
}

整个代码逻辑很简单,就是判断是否有Executor,如果有的话异步加载invokeListener方法,没有的话同步调用invokeListener方法

2.3.1.1.1 getApplicationListeners(eventtype)方法:获取所有监听event事件的监听器

getApplicationListeners方法,主要是判断缓存中有没有已经缓存好的事件,有则直接返回,没有则调用方法retrieveApplicationListeners检索监听器。

AbstractApplicationEventMulticaster.java

protected Collection<ApplicationListener<?>> getApplicationListeners(
        ApplicationEvent event, ResolvableType eventType) {

    Object source = event.getSource();
    Class<?> sourceType = (source != null ? source.getClass() : null);

    // 生成一个用于表示当前这个事件event的缓存key
    ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
    // Potential new retriever to populate
    CachedListenerRetriever newRetriever = null;
    // Quick check for existing entry on ConcurrentHashMap
    // 判断缓存中是不是已经缓存了对该事件感兴趣的监听器
    CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
    // 没有的话,新建一个键值对,并放到map中。这个键值对就用来存放监听这个事件的所有监听器
    if (existingRetriever == null) {
        // Caching a new ListenerRetriever if possible
        if (this.beanClassLoader == null ||
                (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                        (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
            newRetriever = new CachedListenerRetriever();
            existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
            if (existingRetriever != null) {
                newRetriever = null;  // no need to populate it in retrieveApplicationListeners
            }
        }
    }

    // 缓存中有,直接从缓存中获取该事件的监听器并返回
    if (existingRetriever != null) {
        Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
        if (result != null) {
            return result;
        }
        // If result is null, the existing retriever is not fully populated yet by another thread.
        // Proceed like caching wasn't possible for this current local attempt.
    }

    // 缓存中没有,就调用retrieveApplicationListeners方法查找事件ApplicationEvent。
    return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}

2.3.1.1.1.1 retrieveApplicationListeners()

this.defaultRetriever.applicationListeners和this.defaultRetriever.applicationListenerBeans存放了所有的Spring事件,最终会调用supportsEvent方法过滤出对当期事件感兴趣的监听器。

AbstractApplicationEventMulticaster.java

private Collection<ApplicationListener<?>> retrieveApplicationListeners(
            ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {

    List<ApplicationListener<?>> allListeners = new ArrayList<>();
    Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
    Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);
    Set<ApplicationListener<?>> listeners;
    Set<String> listenerBeans;

    synchronized (this.defaultRetriever) {
        // this.defaultRetriever.applicationListeners存放了所有的applicationListeners
        listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
        // this.defaultRetriever.applicationListenerBeans存放的是PayloadApplicationEvent事件
        listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
    }
    // Add programmatically registered listeners, including ones coming
    // from ApplicationListenerDetector (singleton beans and inner beans).
    for (ApplicationListener<?> listener : listeners) {
        // 判断遍历到的监听器是否对当前事件感兴趣
        if (supportsEvent(listener, eventType, sourceType)) {
            if (retriever != null) {
                filteredListeners.add(listener);
            }
            allListeners.add(listener);
        }
    }
    ...............省略
}

事件监听器是什么时候创建并加入到defaultRetriever.applicationListeners中的呢?

我们将监听器注册到事件多播器就会引出一个问题,这里以this.defaultRetriever.applicationListeners为例,this.defaultRetriever.applicationListeners中所有的监听器是什么时候加入进去的呢?

this.defaultRetriever.applicationListeners中包含两种监听器:

  1. 实现了ApplicationListener接口。
  2. @EventListener 注解

1 查找实现了ApplicationListener接口的监听器

这里关键调用ApplicationListenerDetector的postProcessMergedBeanDefinition方法和postProcessAfterInitialization方法(这个方法也就是常说的bean初始化后)。这两个都是BeanPostProcessor的子类提供的方法。

1.1 postProcessMergedBeanDefinition()方法

postProcessMergedBeanDefinition方法的作用很简单,就是判断这个Java类是否实现了ApplicationListener接口,是的话就是一个监听器。然后将这个监听器加入到singletonNames的记录单例Bean的Map中。

ApplicationListenerDetector.java

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    if (ApplicationListener.class.isAssignableFrom(beanType)) {
        this.singletonNames.put(beanName, beanDefinition.isSingleton());
    }
}

1.2 postProcessAfterInitialization()方法

postProcessAfterInitialization方法也很简单,从singletonNames拿到所有的单例ApplicationListener。

并调用this.applicationContext.addApplicationListener((ApplicationListener<?>) bean)方法,前面提到过applicationContext也实现ApplicationEventPublisher接口,拥有事件发布的所有方法,但实际执行的是成员变量applicationEventMulticaster对象。最终就将监听器添加到了this.defaultRetriever.applicationListeners中。

ApplicationListenerDetector.java

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
    if (bean instanceof ApplicationListener) {
        // potentially not detected as a listener by getBeanNamesForType retrieval
        Boolean flag = this.singletonNames.get(beanName);
        if (Boolean.TRUE.equals(flag)) {
            // 拿到所有的单例ApplicationListener并添加到defaultRetriever.applicationListeners
            this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
        }
        else if (Boolean.FALSE.equals(flag)) {
            if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
                // inner bean with other scope - can't reliably process events
                logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
                        "but is not reachable for event multicasting by its containing ApplicationContext " +
                        "because it does not have singleton scope. Only top-level listener beans are allowed " +
                        "to be of non-singleton scope.");
            }
            this.singletonNames.remove(beanName);
        }
    }
    return bean;
}

this.applicationContext.addApplicationListener((ApplicationListener<?>) bean)最终执行的方法其实是AbstractApplicationEventMulticaster类的addApplicationListener方法。

其会最终调用this.defaultRetriever.applicationListeners.add(listener)方法。

AbstractApplicationContext.java

public void addApplicationListener(ApplicationListener<?> listener) {
    Assert.notNull(listener, "ApplicationListener must not be null");
    if (this.applicationEventMulticaster != null) {
        // 调用applicationEventMulticaster.addApplicationListener,来进行监听器的注册
        this.applicationEventMulticaster.addApplicationListener(listener);
    }
    this.applicationListeners.add(listener);
}

 

AbstractApplicationEventMulticaster.java

// 将监听器加入到defaultRetriever.applicationListeners中
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();
    }
}

2 查找加了@EventListener 注解的监听器

我们知道,在生成流程中,会对每个Bean都使用PostProcessor来进行加工。查找加了@EventListener 注解的监听器主要是通过EventListenerMethodProcessor类,由方法名可以看到,这也是一个bean的后置处理器,这个类会在Bean实例化后进行一系列操作。EventListenerMethodProcessor类实现了SmartInitializingSingleton接口,查找@EventListener注解的监听器的功能是通过调用EventListenerMethodProcessor类实现的SmartInitializingSingleton接口的afterSingletonsInstantiated方法来完成,这个方法会在容器初始化完成之后执行。

查找的方式也很简单粗暴,直接调用beanFactory.getBeanNamesForType(Object.class)方法获取Spring容器中的所有对象,然后再去判断这个Bean的方法是否加了@EventListener注解。

EventListenerMethodProcessor.java

@Override
public void afterSingletonsInstantiated() {
    ConfigurableListableBeanFactory beanFactory = this.beanFactory;
    Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
    // 获取Spring容器中的所有Bean的name
    String[] beanNames = beanFactory.getBeanNamesForType(Object.class);

    for (String beanName : beanNames) {
        ................省略
        try {
            // 查找该Bean的方法中是加了@EventListener注解
            processBean(beanName, type);
        }
        catch (Throwable ex) {
            throw new BeanInitializationException("Failed to process @EventListener " +
                    "annotation on bean with name '" + beanName + "'", ex);
        }
    }
                    
}

然后调用processBean()方法,遍历对象中的方法是否有加了EventListener注解的方法。有则调用DefaultEventListenerFactory的createApplicationListener方法创建一个是配置器对象ApplicationListenerMethodAdapter,构造器参数是方法对象,bean类对象,bean对象。最后调用context.addApplicationListener方法把监听器放到this.defaultRetriever.applicationListeners中

EventListenerMethodProcessor.java

private void processBean(final String beanName, final Class<?> targetType) {
    if (!this.nonAnnotatedClasses.contains(targetType) &&
            AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
            !isSpringContainerClass(targetType)) {
        Map<Method, EventListener> annotatedMethods = null;
        try {
            // 遍历对象中的方法是否有加了EventListener注解的方法,将它们都存到annotatedMethods中
            annotatedMethods = MethodIntrospector.selectMethods(targetType,
                    (MethodIntrospector.MetadataLookup<EventListener>) method ->
                            AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
        }
        ..............省略..................
        // 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");
        // 遍历加了EventListener注解的方法
        for (Method method : annotatedMethods.keySet()) {
            // 遍历监听器工厂,这类工厂是专门用来创建监听器的,我们以起作用的是DefaultEventListenerFactory默认工厂为例
            for (EventListenerFactory factory : factories) {
                // DefaultEventListenerFactory是永远返回true的
                if (factory.supportsMethod(method)) {
                    Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
                    // 调用DefaultEventListenerFactory的createApplicationListener的方法,利用该Bean名、Bean类型、方法来创建监听器(其实是适配器类)
                    ApplicationListener<?> applicationListener =
                        factory.createApplicationListener(beanName, targetType, methodToUse);
                    if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                        ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                    }
                    // 把监听器添加到this.defaultRetriever.applicationListeners容器中
                    context.addApplicationListener(applicationListener);
                    break;
                }
            }
        }
    }
}

              

以DefaultEventListenerFactory为例,用默认工厂类来创建监听器(适配器类)ApplicationListenerMethodAdapter。

public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {
    // 省略其余代码
    @Override
    public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
        // 可以看到,每次都是返回一个新对象,每一个加了@EventListener注解的方法就会对应生成一个监听器。例如同一个类中有两个加了@EventListener注解的方法,那么就会生成两个监听器对象
        return new ApplicationListenerMethodAdapter(beanName, type, method);
    }
}

2.3.1.1.1.1.1 supportsEvent(listenereventType) 判断当前监听器是否用来监听该事件

Spring发布事件之后,所有注册的事件监听器,都会收到该事件,因此,事件监听器在处理事件时,需要先判断该事件是否是自己关心的。

所以梳理完了监听器的查找过程,下面我们继续来看看Spring监听器是如何查找感兴趣的事件的。

判断监听器是否用来监听指定事件的逻辑代码还是比较清晰的,先判断当前监听器是不是继承了GenericApplicationListener。如果不是继承GenericApplicationListener的监听器,将会被GenericApplicationListenerAdapter适配器再次包装。

GenericApplicationListener 实现SmartApplicationListener,SmartApplicationListener实现了ApplicationListener接口。但是GenericApplicationListener 的作用是实现了SmartApplicationListener接口的两个方法supportsEventType()和supportsSourceType()。

这两个方法的作用是:

  • supportsEventType(eventType):检查监听器是否支持指定的事件类型。在事件广播过程中,系统会遍历所有的监听器,但并非所有的监听器都对所有类型的事件感兴趣。这个方法用来检查给定的监听器是否对特定类型的事件感兴趣。
  • supportsSourceType(sourceType):检查监听器是否支持指定的事件源类型。有时候,监听器只对特定类型的事件源感兴趣,这个方法用来确定监听器是否支持特定类型的事件源。

这两个方法通常在事件广播器内部使用,用于确定哪些监听器应该接收特定类型的事件。

protected boolean supportsEvent(
        ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
    
    // 如果listener监听器没有继承GenericApplicationListener,就再用GenericApplicationListener将其封装一层
    GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
        (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));

    // 判断监听器是否支持指定的事件类型和事件源类型
    return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

我们来看一下GenericApplicationListener接口源码:

public interface GenericApplicationListener extends SmartApplicationListener {
    @Override
    default boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        return supportsEventType(ResolvableType.forClass(eventType));
    }
    boolean supportsEventType(ResolvableType eventType);
}

从接口方法可以看到GenericApplicationListener 的子类如果没重写supportsEventType方法的话,就表示对所有的事件感兴趣。通过supportsEventType方法,我们可以自定义我们感兴趣的事件。

而相对于GenericApplicationListener接口,适配类GenericApplicationListenerAdapter实现了supportsEventType方法,它的实现就是判断当前监听器的泛型是不是当前事件或者是当前事件的子类(this.declaredEventType.isAssignableFrom(eventType))。

GenericApplicationListenerAdapter.java

public boolean supportsEventType(ResolvableType eventType) {
    if (this.delegate instanceof GenericApplicationListener) {
        return ((GenericApplicationListener) this.delegate).supportsEventType(eventType);
    }
    else if (this.delegate instanceof SmartApplicationListener) {
        Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
        return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
    }
    // 默认实现
    else {
        return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
    }
}

2.3.1.1.2 invokeListener()方法:执行监听器的监听逻辑

SimpleApplicationEventMulticaster.java

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler != null) {
        try {
            doInvokeListener(listener, event);
        }
        catch (Throwable err) {
            errorHandler.handleError(err);
        }
    }
    else {
        doInvokeListener(listener, event);
    }
}


private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
        listener.onApplicationEvent(event);
    }
    catch (ClassCastException ex) {
        String msg = ex.getMessage();
        if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
            // Possibly a lambda-defined listener which we could not resolve the generic event type for
            // -> let's suppress the exception and just log a debug message.
            Log logger = LogFactory.getLog(getClass());
            if (logger.isTraceEnabled()) {
                logger.trace("Non-matching event type for listener: " + listener, ex);
            }
        }
        else {
            throw ex;
        }
    }
}

在doInvokeListener()方法中,终于看到了熟悉的onApplicationEvent方法,这个方法就是我们在自定义监听器时重写的方法,也正是在这里监听器调用了我们自己定义的onApplicationEvent(),实现了当监听器监听到事件发生后,就执行一些自定义的功能。

三、同步与异步

通过模型,我们不难看出,事件的发布其实由业务线程来发起,那么那些监听器的触发呢,是仍由业务线程一个个同步地去通知监听器,还是有专门的线程接手,收到事件后,再转手通知监听器们?

3.1 默认同步通知

其实,因为Spring默认的多播器没有设置执行器,所以默认采用的是第一种情况,即哪个线程发起的事件,则由哪个线程去通知监听器们,关键代码上面已经讲过了,如下所示:

// SimpleApplicationEventMulticaster.java
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            // 默认走此分支,由发出事件的线程来执行
            invokeListener(listener, event);
        }
    }
}

@Nullable
protected Executor getTaskExecutor() {
    return this.taskExecutor;
}

我们可以看到,对于每个监听器的调用是同步还是异步,取决于多播器内部是否含有一个执行器,如果有则交给执行器去执行,如果没有,只能让来源线程一一去通知了。

3.2 异步通知设置

两种方式,一种是在多播器创建时内置一个线程池,使多播器能够调用自身的线程池去执行事件传播。另一种是不在多播器上做文章,而是在每个监视器的响应方法上标注异步@Async注解,毫无疑问,第一种才是正道,我们来看看如何做到。其实有多种方法,我们这里说几种。

3.2.1 第一种,直接自定义一个多播器,然后注册到容器中顶替掉Spring自动创建的多播器

@Configuration
public class EventConfig {
    @Bean("taskExecutor")
    public Executor getExecutor() {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(10,
                15,
                60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue(2000));
        return executor;
    }
    
    // 这其实就是spring-boot自动配置的雏形,所谓的自动配置其实就是通过各种配置类,顶替原有的简单配置
    @Bean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
    public ApplicationEventMulticaster initEventMulticaster(@Qualifier("taskExecutor") Executor taskExecutor) {
        SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
        simpleApplicationEventMulticaster.setTaskExecutor(taskExecutor);
        return simpleApplicationEventMulticaster;
    }
}

3.2.2 第二种,为现成的多播器设置设置一个线程池

@Component
public class WindowsCheck implements ApplicationContextAware {
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SimpleApplicationEventMulticaster caster = (SimpleApplicationEventMulticaster)applicationContext
                .getBean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME);
        ThreadPoolExecutor executor = new ThreadPoolExecutor(10,
                15,
                60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue(2000));
        caster.setTaskExecutor(executor);
    }
}

当然,这里推荐第一种,第二种方法会在Spring启动初期的一些事件上,仍采用同步的方式。直至被注入一个线程池后,其才能使用线程池来响应事件。而第一种方法则是官方暴露的位置,让我们去构建自己的多播器。

3.2.3 第三种,在监听器方法上加@Async注解

@Component
public class OrderEventListener {

    @Async
    @EventListener(OrderEvent.class)
    public void onApplicationEvent(OrderEvent event) {
        if(event.getName().equals("减库存")){
            System.out.println("减库存.......");
        }
    }
}

方法增加@Async注解,表示该方法为异步方法。


相关文章:【Spring框架】Spring监听器的简介和基本使用

猜你喜欢

转载自blog.csdn.net/cy973071263/article/details/133839965