手记

Spring 事件机制


概念

在一个完整的事件体系中、存在以下的角色

  1. 事件:描述发生了什么事情、比如说请求处理完成、Spring 容器刷新完毕

  2. 事件源:事件的产生者、任何一个事件都必须有一个事件源。比如请求处理完成的事件源就是 DispatcherServlet 、Spring 容器刷新完毕的事件源就是 ApplicationContext

  3. 事件广播器:事件和事件监听器的桥梁、负责把事件通知给事件监听器

  4. 事件监听器:监听事件的发生、可以在监听器中做一些处理

Spring 事件

我们常见的事件可能就是 ApplicationContextEvent 、它的子类 ContextRefreshedEvent 是我们常见的事件类型、在 Spring 将所有非延迟加载的 bean 实例化之后发布。

再来看看 Spring 事件的体系结构

Spring 监听器


事件广播器

ApplicationContext 对事件的支持

ApplicationEventPublisher 这个是 Spring 提供给用户使用的一个事件发布器啊、真正实现发布功能还是委托给上面的 ApplicationEventMulticaster 去实现的。

Spring 提供了 ApplicationEventPublisherAware 让用户可以去获取这个发布器进行事件发布。

使用方式

Spring 提供了两种方式

  1. 实现 ApplicationListener 接口

  2. 使用注解 @EventListener

注解的实现源码

我们直接看到 EventListenerMethodProcessor 该类实现了接口 SmartInitializingSingleton 接口、该接口会在 Spring 初始化完所有的非延迟加载的 bean 之后被调用。

 public interface SmartInitializingSingleton {
 
    /**
     * Invoked right at the end of the singleton pre-instantiation phase,
     * with a guarantee that all regular singleton beans have been created
     * already. {@link ListableBeanFactory#getBeansOfType} calls within
     * this method won't trigger accidental side effects during bootstrap.
     * <p><b>NOTE:</b> This callback won't be triggered for singleton beans
     * lazily initialized on demand after {@link BeanFactory} bootstrap,
     * and not for any other bean scope either. Carefully use it for beans
     * with the intended bootstrap semantics only.
     */
    void afterSingletonsInstantiated();
 }

其实实现逻辑非常简单

 for (Method method : annotatedMethods.keySet()) {
    for (EventListenerFactory factory : factories) {
       if (factory.supportsMethod(method)) {
          Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
          ApplicationListener<?> applicationListener =
                factory.createApplicationListener(beanName, targetType, methodToUse);
          if (applicationListener instanceof ApplicationListenerMethodAdapter) {
             ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
          }
          context.addApplicationListener(applicationListener);
          break;
       }
    }
 }

找出所有被注解修饰的方法、然后分别创建一个对应的 ApplicationListener、收到事件后反射调用该方法。

 public void processEvent(ApplicationEvent event) {
    Object[] args = resolveArguments(event);
    if (shouldHandle(event, args)) {
       Object result = doInvoke(args);
       if (result != null) {
          handleResult(result);
       }
       else {
          logger.trace("No result object given - no result to handle");
       }
    }
 }

监听器调用的先后顺序

我们可以在 AbstractApplicationEventMulticaster#retrieveApplicationListeners 中看到是支持我们指定监听器的顺序的、Spring 很多涉及顺序的都可以使用

  1. 实现 Ordered 接口

  2. 实现 PriorityOrdered 接口

  3. 使用 @Ordered 接口


异步调用监听器

默认情况下、Spring 创建的事件广播器是采用同步方式调用通知监听器的、我们可以设置或者替换 Spring 默认的监听器来达到异步调用的目的、当然也可以扩展、根据事件的不同采用同步或者异步的方式、而不是单一的要么所有同步要么所有异步

 @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);
       }
    }
 }

Spring refresh 之前回初始化事件传播器

 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.isTraceEnabled()) {
          logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
       }
    }
    else {
       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() + "]");
       }
    }
 }

替换原来的事件传播器

 @Component("applicationEventMulticaster")
 public class TestEventMulticaster extends SimpleApplicationEventMulticaster {
 }


           

0人推荐
随时随地看视频
慕课网APP