Spring事件监听机制源码分析

Spring事件使用案例

1. 自定义事件

public class MyEvent extends ApplicationEvent {
    private String name;
    public MyEvent(Object source) {
        super(source);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

2. 事件监听器

2.1 实现ApplicationListener 接口
@Component
public class MyEventListener implements ApplicationListener<MyEvent> {
    @Override
    public void onApplicationEvent(MyEvent event) {
        System.out.println("监听到事件:" + event.getSource());
    }
}
2.2 @EventListener注解
@Component
public class MyEventListener{
    @EventListener
    public void onApplicationEvent(MyEvent event) {
        System.out.println("监听到事件:" + event.getSource());
    }
}

另外也可以通过@Async注解实现对事件的异步监听

@EventListener
@Async
public void onApplicationEvent(MyEvent event) {
    System.out.println("监听到事件: " + event.getSource());
}

3. 事件发布

applicationContext.publishEvent(new MyEvent("PUBLISH EVENT1"));

源码解析

1. 如何找到自定义的事件监听器

通过ApplicationListenerDetector实现了BeanPostProcessor接口,在后置处理器中判断如果bean是ApplicationListener类型且是单例的那么进行添加。

private static class ApplicationListenerDetector
      implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {
   private transient final AbstractApplicationContext applicationContext;
   private transient final Map<String, Boolean> singletonNames = new ConcurrentHashMap<String, Boolean>(256);

   @Override
   public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
      if (this.applicationContext != null && beanDefinition.isSingleton()) {
         this.singletonNames.put(beanName, Boolean.TRUE);
      }
   }
   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) {
      return bean;
   }
   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) {
      // 收集事件监听器
      if (this.applicationContext != null && bean instanceof ApplicationListener) {
         // potentially not detected as a listener by getBeanNamesForType retrieval
         Boolean flag = this.singletonNames.get(beanName);
         if (Boolean.TRUE.equals(flag)) {
            // singleton bean (top-level or inner): register on the fly
            // 仅添加单例的bean
            this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
         }
         else if (flag == null) {
            this.singletonNames.put(beanName, Boolean.FALSE);
         }
      }
      return bean;
   }
   @Override
   public void postProcessBeforeDestruction(Object bean, String beanName) {
      if (bean instanceof ApplicationListener) {
         ApplicationEventMulticaster multicaster = this.applicationContext.getApplicationEventMulticaster();
         multicaster.removeApplicationListener((ApplicationListener<?>) bean);
         multicaster.removeApplicationListenerBean(beanName);
      }
   }
   @Override
   public boolean requiresDestruction(Object bean) {
      return (bean instanceof ApplicationListener);
   }
}

AbstractApplicationContext#addApplicationListener 加入到监听列表

public void addApplicationListener(ApplicationListener<?> listener) {
   Assert.notNull(listener, "ApplicationListener must not be null");
   if (this.applicationEventMulticaster != null) {
      this.applicationEventMulticaster.addApplicationListener(listener);
   }
   // 加入到集合中
   this.applicationListeners.add(listener);
}

2. 初始化事件管理器类和注册监听器

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // 准备刷新上下文
      prepareRefresh();
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      prepareBeanFactory(beanFactory);
      try {
         postProcessBeanFactory(beanFactory);
         invokeBeanFactoryPostProcessors(beanFactory);
         registerBeanPostProcessors(beanFactory);
         initMessageSource();
         // 初始化事件管理类
         initApplicationEventMulticaster();
         onRefresh();
         // Check for listener beans and register them.
         // 往事件发布器上注册事件监听器, 事件发布的核心逻辑在这
         registerListeners();
         finishBeanFactoryInitialization(beanFactory);
         // 刷新完成
         finishRefresh();
      }
      catch (BeansException ex) {
      }
      finally {
      }
   }
}

/**
 * 初始化事件发布器
 * 如果上下文没有定义事件发布器的话 使用SimpleApplicationEventMulticaster
 * @see org.springframework.context.event.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);
   }
   else {
      // 如果没有自定义事件发布器,那么spring默认生成一个
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
   }
}

/**
 * 往事件发布器上注册事件监听器, 事件发布的核心逻辑在这
 * Add beans that implement ApplicationListener as listeners.
 * Doesn't affect other listeners, which can be added without being beans.
 */
protected void registerListeners() {
   // Register statically specified listeners first.
   // 注册特殊的监听器
   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监听器名称列表, 例如我们自定义的事件监听都在这里
   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   for (String listenerBeanName : listenerBeanNames) {
      // 把这些beanName添加到applicationListenerBeans监听器列表里,当事件发布时,通知这些beanName
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   }

   // Publish early application events now that we finally have a multicaster...
   // 添加事件监听器后, 判断是否有earlyApplicationEvents, 如果有就使用事件发布器进行广播
   // earlyApplicationEvents表示在事件发布器还没有生成之前ApplicationContext需要发布的事件
   Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
   this.earlyApplicationEvents = null;
   if (earlyEventsToProcess != null) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}

事件发布重要方法 SimpleApplicationEventMulticaster#multicastEvent

@Override
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();
      // 如果设置了线程池,那么异步执行否则同步执行 
      if (executor != null) {
         executor.execute(new Runnable() {
            @Override
            public void run() {
               // 执行监听器方法
               invokeListener(listener, event);
            }
         });
      }
      else {
         // 执行监听器方法
         invokeListener(listener, event);
      }
   }
}

// 执行监听器方法
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
    // 执行onApplicationEvent方法
    listener.onApplicationEvent(event);
}

其中注意点

2.1 上下文属性 AbstractApplicationContext #earlyApplicationEvents

这是用于存储发布器初始化之前的事件列表

/** ApplicationEvents published early */
private Set<ApplicationEvent> earlyApplicationEvents;

一旦事件发布器可用 立即被发布

public void refresh() throws BeansException, IllegalStateException {
    //Prepare this context for refreshing.
    prepareRefresh();
    // ...
}
// 在这里初始化了该事件列表
protected void prepareRefresh() {
   // Initialize any placeholder property sources in the context environment
   initPropertySources();

   // Validate that all properties marked as required are resolvable
   // see ConfigurablePropertyResolver#setRequiredProperties
   getEnvironment().validateRequiredProperties();

   // Allow for the collection of early ApplicationEvents,
   // to be published once the multicaster is available...
   this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
2.2 Spring 生命周期内置的事件监听

finishRefresh完成刷新时,发布了一个ContextRefreshedEvent事件。

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.
   if (!NativeDetector.inNativeImage()) {
      LiveBeansView.registerApplicationContext(this);
   }
}

关于spring上下文生命周期发布事件的场景如下

  • AbstractApplicationContext#start

  • AbstractApplicationContext#stop

  • AbstractApplicationContext#refresh#finishRefresh

  • AbstractApplicationContext#registerShutdownHook#doClose

image-20231103095312290

image-20231103095316904

3. 事件发布真正调用的方法AbstractApplicationContext#publishEvent

protected void publishEvent(Object event, ResolvableType eventType) {
   // Decorate event as an ApplicationEvent if necessary
   ApplicationEvent applicationEvent;
   if (event instanceof ApplicationEvent) {
      applicationEvent = (ApplicationEvent) event;
   }
   else {
      applicationEvent = new PayloadApplicationEvent<Object>(this, event);
      if (eventType == null) {
         eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
      }
   }
   // 如果earlyApplicationEvents不为空(prepareRefresh里面进行了初始化),那么加入发布器的事件列表
   // 等待事件发布器准备好再进行广播
   // 否则立即进行广播
   // 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);
      }
   }
}

至于SimpleApplicationEventMulticaster#multicastEvent方法上文已经分析过了,不做赘述。

4. @EventListener注解方式的监听器是怎么处理的

通过EventListenerMethodProcessor,实现了SmartInitializingSingleton接口,在Bean实例化结束之后调用afterSingletonInstantiated()方法对每个单例Bean进行处理,如果一个方法上有@EventListener注解,那么会把方法包装成事件监听器。

@Override
public void afterSingletonsInstantiated() {
    ConfigurableListableBeanFactory beanFactory = this.beanFactory;
    Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
    String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
    for (String beanName : beanNames) {
        //...
        try {
            processBean(beanName, type);
        }
        catch (Throwable ex) {
            throw new BeanInitializationException("Failed to process @EventListener " +
                    "annotation on bean with name '" + beanName + "'", ex);
        }   
    }
}

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 = MethodIntrospector.selectMethods(targetType,
                    (MethodIntrospector.MetadataLookup<EventListener>) method ->
                            AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
        }
        catch (Throwable ex) {
            // ...
        }

        if (CollectionUtils.isEmpty(annotatedMethods)) {
            // ...
        }
        else {
            // 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");
            for (Method method : annotatedMethods.keySet()) {
                for (EventListenerFactory factory : factories) {
                    if (factory.supportsMethod(method)) {
                        Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
                        // 将加了@EventListener注解的方法生成applicationListener类
                        ApplicationListener<?> applicationListener =
                                factory.createApplicationListener(beanName, targetType, methodToUse);
                        if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                            ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                        }
                        // 添加到applicationListeners列表中
                        context.addApplicationListener(applicationListener);
                        break;
                    }
                }
            }
            //...
        }
    }
}

当发布事件时, getApplicationListeners(event, type)获取到的ApplicationListener里面有上面生成的ApplicationListenerMethodAdapter包装类。最后调用包装对象的processEvent方法

public void processEvent(ApplicationEvent event) {
   Object[] args = resolveArguments(event);
   if (shouldHandle(event, args)) {
      // 反射执行@EventListener标注的方法
      Object result = doInvoke(args);
      if (result != null) {
         handleResult(result);
      }
      else {
         logger.trace("No result object given - no result to handle");
      }
   }
}

【本文完】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值