美文网首页
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