• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

【Spring注解】事件监听:ApplicationListener和@EventListener注解

互联网 diligentman 2周前 (01-13) 11次浏览

监听器

  • ApplicationListener用法
    • 写一个监听器
    • 发布事件
  • ApplicationListener原理
    • 多播器
    • 注册监听器
    • 发布事件 监听器方法回调
      • 发布事件的流程
  • @EventListener用法
  • @EventListener原理

监听器的实现有两种方式:

  • 实现ApplicationListener接口
  • 加@EventListener

ApplicationListener用法

ApplicationListener通过监听容器中发布的一些事件,事件发生就会触发监听器的回调,就完成了事件驱动开发

写一个监听器

  • 写一个监听器监听某个事件
    • 实现ApplicationListener
    • 把监听器加入到容器中

只要容器中有相关事件发布,我们就能监听到这个事件
【Spring注解】事件监听:ApplicationListener和@EventListener注解
测试结果:
监听到的两个事件
【Spring注解】事件监听:ApplicationListener和@EventListener注解

发布事件

我们也可以自己发布事件

        // 发布事件
        applicationContext.publishEvent(new ApplicationEvent(new String("我发布的事件")) {
   
   
        });

【Spring注解】事件监听:ApplicationListener和@EventListener注解

ApplicationListener原理

创建ioc容器,调用refresh()方法

  • 第一步:多播器/派发器
    this.initApplicationEventMulticaster();
    
  • 第二步:注册监听器
    this.registerListeners();
    
  • 第三步:发布事件 监听器方法回调
    不管是什么事件, 都是通过publishEvent()发布事件的流程是一样的,只是创建事件的位置不一样
    • ContextRefreshedEvent 事件
      this.finishRefresh(); //ContextRefreshedEvent 事件在这里
      
    • 自己发布事件(不是在refresh())
    • 容器关闭事件(不是在refresh())

多播器

容器创建对象refresh() 中调用initApplicationEventMulticaster就是初始化EventMulticaster的
initApplicationEventMulticaster() 方法:
* 先去容器中找id=“applicationEventMulticaster”的
* 容器中没有就创建SimpleApplicationEventMulticaster
* 将创建好的加入到beanFactory
【Spring注解】事件监听:ApplicationListener和@EventListener注解

注册监听器

容器创建对象refresh() 中调用ApplicationListener()就是注册监听器的
ApplicationListener()方法:
就是从容器中拿到所有的监听器,把他们注册到ApplicationEventMulticaster中
【Spring注解】事件监听:ApplicationListener和@EventListener注解

发布事件 监听器方法回调

  1. ContextRefreshedEvent
    默认的事件:ContextRefreshedEvent,容器刷新完成事件
    所以在refresh() 的finishRefresh()方法中 会发布ContextRefreshedEvent事件,然后触发监听器。

    finishRefresh() 如下
    【Spring注解】事件监听:ApplicationListener和@EventListener注解
    finishRefresh() 调用的publishEvent() 方法如下:【Spring注解】事件监听:ApplicationListener和@EventListener注解

  2. 我们自己写的发布事件
    【Spring注解】事件监听:ApplicationListener和@EventListener注解
    也是会调用发布事件的流程的publishEvent()
    【Spring注解】事件监听:ApplicationListener和@EventListener注解

  3. 容器关闭发布事件 ContextClosedEvent
    【Spring注解】事件监听:ApplicationListener和@EventListener注解
    【Spring注解】事件监听:ApplicationListener和@EventListener注解
    doClose()方法也会调用publishEvent() 方法
    【Spring注解】事件监听:ApplicationListener和@EventListener注解

发布事件的流程

publishEvent():

  • 获取事件的派发器/多播器getApplicationEventMulticaster()

  • 派发事件 multicastEvent
    【Spring注解】事件监听:ApplicationListener和@EventListener注解

    获取到所有的ApplicationListeners,依次遍历

    • 有Executor 则异步派发
    • 无Executor 同步的方式直接执行listener方法
      invokeListener调用doInvokeListener
      把当前的listener拿到回调它的onApplicationEvent方法【Spring注解】事件监听:ApplicationListener和@EventListener注解

@EventListener用法

在想监听事件的方法上加上@EventListener注解,注解中指定要监听哪种类型的事件
然后在方法上写上参数,获得监听到的事件
【Spring注解】事件监听:ApplicationListener和@EventListener注解
看结果和实现ApplicationListener接口的结果是一样的
【Spring注解】事件监听:ApplicationListener和@EventListener注解

@EventListener原理

原理是:用EventListenerMethodProcessor处理器来解析方法上的@EventListener注解

public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor 

EventListenerMethodProcessor实现了SmartInitializingSingleton接口,这个接口如下:
有一个afterSingletonsInstantiated方法:
这个方法在所有单实例bean全部创建完成后 执行
【Spring注解】事件监听:ApplicationListener和@EventListener注解
在EventListenerMethodProcessor的afterSingletonsInstantiated方法处打一个断点,看运行流程如下:

  • 创建ioc容器,refresh() 方法刷新容器

  • 执行refresh() 中的finishBeanFactoryInitialization(beanFactory)
    初始化剩下的单实例bean
    【Spring注解】事件监听:ApplicationListener和@EventListener注解

  • 调用preInstantiateSingletons()方法
    在finishBeanFactoryInitialization中调用

    beanFactory.preInstantiateSingletons();
    
  • preInstantiateSingletons()
    得到所有的beanDefinitionNames,依次遍历,是SmartInitializingSingleton类型的就调用其afterSingletonsInstantiated方法【Spring注解】事件监听:ApplicationListener和@EventListener注解

然后就把这个标 了@EventListener注解的方法弄成listener,之后发布事件的时候 就会回调这个方法

问题是什么时候弄成listener的????

{{o.name}}


{{m.name}}


喜欢 (0)