美文网首页
Spring 事件机制源码分析

Spring 事件机制源码分析

作者: 逗逗罗 | 来源:发表于2020-12-10 15:06 被阅读0次
    前言

    上一篇 Spring 事件机制概述 的文章中,从观察者模式、Java 事件机制、Spring 事件机制的具体代码实现进行了简要的分析。本篇文章将在其基础上对 Spring 事件机制的源码进行分析。

    • Spring 事件机制流程回顾
      1. 创建一个具体的事件类,该类需继承 ApplicationEvent;
      2. 创建一个针对某个特定时间的监听器实现 ApplicationListener,并配置 @Component 注解,确保 Ioc 容器启动时,监听器会注入至 Ioc 容器;
      3. 初始化 Ioc 容器;
      4. 由于 ApplicationContext 实现了 ApplicationEventPublisher,因此直接使用 ApplicationContext 作为事件发布器发布某个事件,此时该事件的监听器便会接收到事件并做出相应的处理。此处也可以通过实现 ApplicationEventPublisherAware 接口,来获得事件发布器。

    上述的流程中,可能会有这样一些疑问:

    1. 事件监听器是何时被注入的?
    2. 事件发布器是怎么样对具体的事件进行发布?

    带着这两个疑问,开始源码的分析。

    Spring 事件机制源码分析

    在实际应用的代码中,Ioc 容器 ApplicationContext 创建完成后,监听器 ApplicationListener 及发布器 ApplicationEventPublisher 均已就绪,可直接使用进行事件发布,故从 ApplicationContext 初始化着手来分析。 通过对 Spring Ioc 的源码分析,我们知道了容器初始化的核心方法为 AbstractApplicationContext::refresh,查看 refresh 方法,我们发现有两个方法与 Spring 的事件相关。

    1. initApplicationEventMulticaster 方法

      • ApplicationEventMulticaster(事件多播器)
        ApplicationEventMulticaster 接口的方法主要是操作 ApplicationListener, 广播 ApplicationEvent

        public interface ApplicationEventMulticaster {
            void addApplicationListener(ApplicationListener<?> listener);
            void addApplicationListenerBean(String listenerBeanName);
            void removeApplicationListener(ApplicationListener<?> listener);
            void removeApplicationListenerBean(String listenerBeanName);
            void removeAllListeners();
            void multicastEvent(ApplicationEvent event);
            void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
        }
        

        分析其继承关系,在抽象类 AbstractApplicationEventMulticaster 中实现了接口的方法,SimpleApplicationEventMulticaster 中引入异步操作的支持。相关源码会在后面串联分析。


        ApplicationEventMulticaster
      • 源码
        源码的核心流程是,先判断 BeanFactory 中有没有 ApplicationEventMulticaster 类,若有则赋值给本地变量,若无则创建 SimpleApplicationEventMulticaster 并赋值给本地变量。

        protected void initApplicationEventMulticaster() {
            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 + "]");
                }
            }
        }
        
    2. registerListeners

      • 源码分析
        从 registerListeners 源码中可以看到,该方法中只是将 ApplicationListener 对应的 BeanName 保存起来了,因此这个时候 Bean 都还没有完成初始化,只有 beanDefinition 的信息,后续在完成 Bean 初始化后,会调用一个后置处理器 ApplicationListenerDetector 的 postProcessAfterInitialization 方法,将 ApplicationListener 对应的 Bean 实例绑定到 ApplicationEventMulticaster 中。
      protected void registerListeners() {
          // Register statically specified listeners first.
          // getApplicationListeners 方法中返回本地的 applicationListeners
          for (ApplicationListener<?> listener : getApplicationListeners()) {
              getApplicationEventMulticaster().addApplicationListener(listener);
          }
      
          // Do not initialize FactoryBeans here: We need to leave all regular beans
          // uninitialized to let post-processors apply to them!
          // 从 BeanFactory 中找到 ApplicationListener 类所对应的所有 BeanName
          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;
          this.earlyApplicationEvents = null;
          if (earlyEventsToProcess != null) {
              for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                  getApplicationEventMulticaster().multicastEvent(earlyEvent);
              }
          }
      }
      

    在完成 ApplicationEventMulticaster 初始化,监听器注入后,后续就是如何发布事件,从 ApplicationContext 的类继承关系中知道,该类继承了 ApplicationEventPublisher,在 AbstractApplicationContext 类中实现了方法 publishEvent,具体源码为:

    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");
        if (logger.isTraceEnabled()) {
            logger.trace("Publishing event in " + getDisplayName() + ": " + event);
        }
    
        // 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);
            }
        }
    }
    
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        // getApplicationListeners 根据 event 的类型找到相应的 listener
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            // 增加了对异步事件的支持,如果 executor 不为空则异步通知该事件
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                invokeListener(listener, event);
            }
        }
    }
    
    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.isDebugEnabled()) {
                    logger.debug("Non-matching event type for listener: " + listener, ex);
                }
            }
            else {
                throw ex;
            }
        }
    }
    
    总结

    从上述的分析中可知,Spring 事件发布的主要流程为:

    1. 初始化 事件多播器(ApplicationEventMulticaster)
    2. 注册 ApplicationListener
    3. 调用后置处理器 ApplicationListenerDetector 完成 ApplicationEventMulticaster 中 listener 实例的赋值;
    4. 发布事件时,调用 ApplicationEventMulticaster 的广播方法,将 Event 广播至对应的 Listener。

    Spring 提供了以下 5 中标准的事件,我们可以注册响应的监听器进行处理该事件。

    1. 上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
    2. 上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
    3. 上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
    4. 上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。
    5. 请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。

    相关文章

      网友评论

          本文标题:Spring 事件机制源码分析

          本文链接:https://www.haomeiwen.com/subject/zofrgktx.html