Springboot事件监听机制:工作原理

目录

前言

1.观察者模式

1.1观察者模式的核心元素

1.2观察者模式的工作流程

2.springboot事件监听机制的基本工作原理

2.1事件发布器是什么时候在哪里产生的呢?

2.2事件监听器是什么时候怎么注册到事件发布器里去了呢

2.3事件发布器发布事件后,发生了什么?是怎么执行的监听器的回调方法了呢?

3.总结


前言

        这是继《springboot事件监听机制一:实战应用》第二篇,知其然,当然还要知其所以然,深入的源码里面探寻一下这一有套机制的工作原理。spring生态很茂盛,这里不会站太高去分析这个问题,大扯spring的一些原理,而是以一个求知者的心态去探索spring监听机制的秘密,可能我分析得并不透彻,但我想如果能给看到这篇文章的你带去一些灵感或者触动也是好的。罗马不是一天就能建立起来的,想要弄懂它也非一天的事,多想多看总会明白的。另外看源码的时候,一定是带着问题去探寻,时刻把握好问题的核心,切忌被旁枝末节打扰而迷失的源码里了(如果对一旁枝末节实在很感兴趣,可以先记录下来位置,之后再来探寻)。发现问题,然后解决问题,这就是进步!现在一起来进步吧!

1.观察者模式

1.1观察者模式的核心元素

 springboot事件监听机制的原理是观察者模式,观察者模式有几个核心的元素:

  • 事件源
  • 事件
  • 事件发布器
  • 监听器

1.2观察者模式的工作流程

  1.   事件监听器注册到事件发布器,用于监听事件
  2.   事件源产生事件,然后向发布器发布事件,
  3.   事件发布器回调已注册的监听器的回调方法
  4.   事件监听器的回调方法被调用

2.springboot事件监听机制的基本工作原理

        正如上一篇文章中的示例,把各业务中的短信发送需求抽象成一个短信发事件,在各业务需要发送短信的时候,就通过事件发布器来发布事件,然后触发短信发送监听器里的发送短信操作一样,Spring生态这么庞大,功能也多,自身的事件自不会少,如容器启动、容器刷新、关闭、停止等都是一个事件。为什么会这样呢?这是因为Spring容器在初始化、启动、刷新、关闭等这些过程中,也需要通知其他模块,所以spring自身也有很多事件也就不奇怪了。 但是这么多事件,功能不一样,但是本质是相同的,所有事件一基类都是java.util.EventObject。所以下面还是以上一篇文章中的短信发布事件作为例子,来探寻一下springboot的事件监听的工作原理。

         在上一篇的例子中,封装好短信事件,同是也把短信监听器通过@component注解注册到了spring容器里,然后就在业务中直接通过事件发布器(ApplicationEventPublisher)发布了,这中间许多细节是什么样的呢?比如:

  • 事件发布器是什么时候在哪里产生的呢?
  • 事件监听器是什么时候什么注册到事件发布里去了呢
  • 事件发布器发布事件后,是怎么执行的监听器的回调方法了呢?

2.1事件发布器是什么时候在哪里产生的呢?

        事件发布器实例化的入口AbstractApplicationContext#refresh中调用了AbstractApplicationContext#initApplicationEventMulticaster,最后实际会实例出一个SimpleApplicationEventMulticaster对象,这个对象一般都翻译成事件广播器,他的作用就是发布事件、接受监听器的注册、回调监听器中的回调方法。眼尖的人都看出来了,在业务类里注册的事件发布器是ApplicationEventPublisher,不是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.isTraceEnabled()) {
         logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
      }
   }else {
       //spring容器启动的时候,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() + "]");
      }
   }
}

2.2事件监听器是什么时候怎么注册到事件发布器里去了呢

        事件监听器注册到事件发布器里的逻辑在这个方法:AbstractApplicationContext#registerListeners,而registerListeners()也是在refresh()里被调用的

protected void registerListeners() {
   // Register statically specified listeners first.
   for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
   }
   //smsListener通过@Component注册到spring容器里后,在这里注册到spring的事件广播器里
   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   }
   Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
   this.earlyApplicationEvents = null;
   if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}

2.3事件发布器发布事件后,发生了什么?是怎么执行的监听器的回调方法了呢?

        顺着UserService#registe()里的this.applicationEventPublisher.publishEvent(),使劲往里面找,最后找到了AbstractApplicationContext#publishEvent(java.lang.Object),到这感觉出来点啥没,所有的逻辑都指向AbstractApplicationContext类,这里先按下不表,继续往下找事件是发布到哪了,最后在AbstractApplicationContext#publishEvent(Object, ResolvableType)里找到了一句 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType),顺着getApplicationEventMulticaster(),再往下找到spring的事件广播器接口ApplicationEventMulticaster,SimpleApplicationEventMulticaster是ApplicationEventMulticaster接口的实现类,这下明白在第一个问题中疑问了吧,表面上的事件发布器是ApplicationEventPublisher,而实际最终执行发布事件的是SimpleApplicationEventMulticaster。

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

        到这里,只是找到了通过this.applicationEventPublisher.publishEvent()找到了发布事件的实际干活人(SimpleApplicationEventMulticaster),它是怎么干活的呢?

沉住气,继续向里面翻SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent, ResolvableType)后,仔细看一下里面的逻辑:先看一下有没有线程池可用,如果有,就用,如果没有,就不用,直接执行监听器里的回调方法onApplicationEvent(),最后找到了SmsListener中具体执行发短信操作的onApplicationEvent();

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

3.总结

        Spring事件的发布器的实例化、Spring事件监听器注册到事件发布器、Spring事件的发布都指向一个类AbstractApplicationContext,其中Spring事件的发布器的实例化、Spring事件监听器注册到事件发布器都是在AbstractApplicationContext#refresh()里完成,了解spring bean的生命周期的小伙伴,对这个方法肯定不陌生,这可是spring容器启动的灵魂,因此玩好spring,bean的生命周期必须玩透。到这里spring事件监听机制的工作原理基本摸清楚了,很多关键的事情,如事件发布器的实例化、事件监听器的注册这些都在spring容器启动的时候就开始了。这些关系理清楚后,才突然发现:真的是大道至简,牛逼就是简单,简单就是牛逼,致敬spring!

<think>好的,我现在需要解释Spring Boot监听器的工作原理和实现机制。首先,我得回忆一下Spring框架中的事件机制,因为Spring Boot的监听器是基于这个的。Spring使用ApplicationEvent和ApplicationListener来实现事件驱动模型,用户可以通过发布和监听事件来实现组件间的松耦合通信。 接下来,Spring Boot在启动过程中会触发多种事件,比如ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent等。这些事件对应不同的启动阶段,监听器需要注册到Spring应用中才能响应这些事件。这时候可能需要提到Spring Boot如何自动加载监听器,比如通过spring.factories文件或者使用@EventListener注解。 然后,要分步骤说明工作原理。首先是事件的定义和发布,然后是监听器的注册,最后是事件的处理机制。需要提到ApplicationContext在事件机制中的作用,因为它负责管理事件发布和监听器的调用。 实现机制方面,要区分基于接口的ApplicationListener和基于注解的@EventListener两种方式。可能还需要提到Spring Boot特有的SpringApplicationRunListener接口,以及如何通过SpringApplication的addListeners方法添加自定义监听器。 另外,要注意Spring Boot的事件触发顺序,不同阶段的事件在启动过程中的顺序很重要,比如ApplicationStartingEvent是在启动最开始触发,而ApplicationReadyEvent是在应用完全启动后触发。这有助于用户理解监听器的执行时机。 可能还需要举一个简单的例子,比如自定义一个监听器并实现某个事件的处理,这样用户能更直观地理解实现步骤。同时,要提到配置监听器的方式,比如通过属性文件或编程方式添加。 最后,检查是否有遗漏的关键点,比如监听器的执行线程,是否是同步还是异步,以及如何配置异步处理。此外,可能还需要对比Spring的事件机制Java的事件机制,说明Spring Boot在此基础上的扩展。 总结下来,需要结构清晰地分点讲解,结合工作原理和实现机制,并给出相关的问题供用户进一步学习。</think>### Spring Boot 监听器工作原理及实现机制 #### 一、核心原理 Spring Boot 监听器基于**观察者模式**实现,通过事件驱动机制在应用生命周期不同阶段触发特定操作。其核心是`ApplicationEvent`和`ApplicationListener`接口,工作流程如下: 1. **事件定义** Spring Boot 内置了多种标准事件类,例如: - `ApplicationStartingEvent`:应用启动时立即触发 - `ApplicationEnvironmentPreparedEvent`:环境准备完成时触发 - `ApplicationReadyEvent`:应用完全就绪时触发 2. **事件发布** 通过`ApplicationContext`的`publishEvent()`方法发布事件: ```java context.publishEvent(new CustomEvent(data)); ``` 3. **监听器注册** 两种主要注册方式: - **接口实现**:实现`ApplicationListener<事件类型>`接口 ```java public class MyListener implements ApplicationListener<ApplicationStartingEvent> { @Override public void onApplicationEvent(ApplicationStartingEvent event) { // 处理逻辑 } } ``` - **注解驱动**:使用`@EventListener`注解 ```java @EventListener public void handleContextRefresh(ContextRefreshedEvent event) { // 处理逻辑 } ``` 4. **事件处理** Spring 通过`ApplicationEventMulticaster`统一调度监听器,默认使用**同步执行**模式,可通过`@Async`配置异步处理[^1]。 #### 二、实现机制 1. **启动阶段监听** Spring Boot 通过`SpringApplicationRunListener`接口管理启动过程: ```java public interface SpringApplicationRunListener { void starting(ConfigurableBootstrapContext bootstrapContext); void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment); // 其他阶段方法 } ``` 2. **自动配置集成** 通过`META-INF/spring.factories`注册监听器: ```properties org.springframework.context.ApplicationListener=\ com.example.MyListener ``` 3. **自定义监听器** 实现步骤: ```java // 1. 定义事件类 public class CustomEvent extends ApplicationEvent { public CustomEvent(Object source) { super(source); } } // 2. 创建监听器 @Component public class CustomEventListener { @EventListener public void handleEvent(CustomEvent event) { System.out.println("Received custom event"); } } // 3. 发布事件 @Autowired private ApplicationEventPublisher publisher; publisher.publishEvent(new CustomEvent(this)); ``` #### 三、关键特性 | 特性 | 说明 | |------|------| | 执行顺序 | 可通过`@Order`注解控制监听器执行顺序 | | 条件过滤 | 使用`condition`属性指定触发条件:<br>`@EventListener(condition = "#event.flag == true")` | | 异步处理 | 需配合`@EnableAsync`和线程池配置 | ```mermaid graph TD A[事件发布者] -->|发布事件| B(ApplicationEventMulticaster) B --> C{监听器列表} C --> D[监听器1] C --> E[监听器2] C --> F[监听器3] ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凡夫贩夫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值