前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring5.x-监听器原理及源码实现

spring5.x-监听器原理及源码实现

作者头像
逍遥壮士
发布2023-09-01 17:05:53
2540
发布2023-09-01 17:05:53
举报
文章被收录于专栏:技术趋势

基础知识

Spring框架的事件机制允许对象在特定的事件发生时进行监听和响应。Spring监听器的原理主要涉及以下几个核心概念:

  1. 事件:Spring中的事件是指应用程序中发生的各种动作或状态的变化,例如对象创建、方法调用、异常抛出等。
  2. 事件源:事件源是触发事件的对象,它通常会通过发布者(Publisher)来触发事件。
  3. 事件监听器:事件监听器是一个接口,定义了对特定事件的监听和处理方法。它可以注册到应用程序上下文中,以便在事件发生时被调用。
  4. 事件发布器(广播器):事件发布器负责管理事件的发布和事件监听器的注册。在Spring中,ApplicationContext就是事件发布器的实现,它能够发布事件并将其传递给已注册的事件监听器。

Spring监听器的工作流程如下:

  1. 创建事件对象:当某个事件发生时,首先需要创建表示该事件的对象。
  2. 发布事件:事件对象被传递给事件发布器(即ApplicationContext),发布器通过遍历注册的监听器列表,将事件分发给对应的监听器。
  3. 监听器的执行:监听器接收到事件后,调用事件处理方法进行处理。监听器的数量和顺序由注册顺序决定,事件处理方法可以执行任意的业务逻辑。

Spring监听器的原理就是通过事件、事件源、事件监听器和事件发布器之间的协作来实现对应用程序中事件的监听和响应。这种机制使得应用程序能够更加灵活地处理各种动态变化,提高了系统的可扩展性和可维护性。

事件:类图

事件类名

作用

备注

ContextRefreshedEvent

事件被发布当ApplicationContext被初始化或者刷新时,它可以由refresh()方法引起在ConfigurableApplicationtext接口中。

ContextStartedEvent

事件被发布当ApplicationContext通过ConfiugrableApplication()接口的start()方法启动时。你可以查询数据库或者你可以重新启动任何停止的应用在收到这个事件后。

ContextStoppedEvent

事件被发布当ApplicationContext通过ConfigurableApplication接口的stop()方法停止时。你可以做必须的看家工作在收到这个事件时。

ContextClosedEvent

事件被发布当ApplicationContext通过ConfigurableApplicationContext接口的close()方法关闭时。一个关闭的上下文到达它声明的终点,不能在被刷新或者重启。

RequestHandledEvent

这是一个web专有的事件,告诉所有beans有一个HTTP请求已经被处理。

用于http请求及响应的监听器

基本使用

几年前写过一个spring事件文章,可以参考:spring的事件

实现原理

spring内置事件

其实很容易可以看出来,该原理就是使用观察者模式来进行监听,这种好比,最近特大洪水事件:新闻联播(多播器)通告近日由于受台风影响,导致多省洪涝严重(事件),各地收到该信息(监听器)纷纷发起抢险救灾行动。

ApplicationEventMulticaster监听机制

spring还有另外一种ApplicationEventMulticaster监听机制,它的作用是接收发布者发布的事件,并将事件传递给已注册的监听器进行处理。

与前面提到的RequestHandledEvent不同,ApplicationEventMulticaster是一个更通用的事件广播机制,用于在整个Spring应用程序中分发各种类型的事件。

ApplicationEventMulticaster的主要作用有以下几点:

  1. 注册监听器:开发人员可以使用ApplicationEventMulticaster的addApplicationListener()方法注册监听器,以便在事件广播时能够接收和处理感兴趣的事件。
  2. 广播事件:一旦事件被发布者(ApplicationEventPublisher)发布,ApplicationEventMulticaster将会接收到该事件,并通过调用已注册的监听器的相应方法将事件广播出去。监听器可以根据事件类型进行匹配并执行自定义的处理逻辑。
  3. 异步事件广播:ApplicationEventMulticaster还支持异步事件广播,即事件的处理可以在单独的线程中进行,不会阻塞当前线程。这可以提高应用程序的性能和响应能力。

ApplicationEventMulticaster是Spring框架中负责事件广播的机制,它能够接收发布者发布的事件,并将其传递给已注册的监听器进行处理。它与RequestHandledEvent不同,RequestHandledEvent是Spring提供的特定事件类,用于在处理HTTP请求后触发,而ApplicationEventMulticaster是一种通用的事件广播机制,用于整个Spring应用程序中分发各种类型的事件。

类图:

源码学习

监听器的实始化

代码位置:org.springframework.context.support.AbstractApplicationContext#prepareRefresh

代码语言:javascript
复制
...
//创建初始化事件监听器
if (this.earlyApplicationListeners == null) {
      this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
    }
    else {
      // Reset local application listeners to pre-refresh state.
      this.applicationListeners.clear();
      this.applicationListeners.addAll(this.earlyApplicationListeners);
    }

    /** 初始化事件列表,自动将初始化事件监听器(自动添加不需要pubish)
     */
    this.earlyApplicationEvents = new LinkedHashSet<>();

代码位置:org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory

代码语言:javascript
复制
...
//注册后置处理器用来处理ApplicationContextAware接口的回调方法
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
...

代码位置:org.springframework.context.support.AbstractApplicationContext#refresh

代码语言:javascript
复制
...
// 注册事件多播器
        initApplicationEventMulticaster();

...
//事件监听器注册到多播器上
        registerListeners();

注意下面这个是手动去注册进去的

代码位置:org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster

代码语言:javascript
复制
/**事件多播器初始化 **/
protected void initApplicationEventMulticaster() {
    //获取bean工厂
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    //如果没有多播器则应用多播器组件
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      //获取bean中的对象(提前初始化的)
      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 + "]");
      }
    }
  }

代码位置:org.springframework.context.support.AbstractApplicationContext#registerListeners

代码语言:javascript
复制
/**初始化和懒加载都会调用注册 **/
protected void registerListeners() {
    //获取所有监听器对象 
    for (ApplicationListener<?> listener : getApplicationListeners()) {
      //把监听器注册到多播器上
      getApplicationEventMulticaster().addApplicationListener(listener);
    }

    //获取自定的监听器
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    //同样把自定义的监听器注册到多播器中
    for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    //获取初始化监听器
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    //将所有初始化的监听器置为空并进行广播(清空掉)
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
      //通过多播器进行播发早期事件
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
        getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
    }
  }

发布事件监听器

代码位置:org.springframework.context.support.AbstractApplicationContext#finishRefresh

代码语言:javascript
复制
...
// 发布事件多播器
    publishEvent(new ContextRefreshedEvent(this));
...
代码语言:javascript
复制
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();
      }
    }

    //发布初始化(早期)事件,唯一的地方
    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);
      }
    }
  }

到这里初始化完毕所有监听器。

监听器的使用

注意,spring默认的事件广播器为:org.springframework.context.event.SimpleApplicationEventMulticaster,如果不指定默认为它,且默认为同步。

通过方法multicastEvent实现监听

代码语言:javascript
复制
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
  ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
  //获取所有监听器
  for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
    //获取异常支持,有则是异常事件,否则是同步发
    Executor executor = getTaskExecutor();
    if (executor != null) {
      //异步播发事件
      executor.execute(() -> invokeListener(listener, event));
    }
    else {//同步发
      invokeListener(listener, event);
    }
  }
}

最后

很多中间件就是通过spring支持默认监听机制实现的,当然看具体实现方式和场景有兴趣的同学可以看看nacos、dubbo、mq等中都有集成的场景,在后续有机会再根据现在的基础进行学习。

参考文章:

https://www.cnblogs.com/shigongp/p/16685903.html

https://blog.csdn.net/biaolianlao0449/article/details/104246732/

https://blog.51cto.com/u_15346609/5646215

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 技术趋势 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基础知识
  • 基本使用
  • 实现原理
    • spring内置事件
      • ApplicationEventMulticaster监听机制
        • 类图:
    • 源码学习
      • 监听器的实始化
        • 监听器的使用
        • 最后
        相关产品与服务
        消息队列 TDMQ
        消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档