请选择 进入手机版 | 继续访问电脑版

Spring源码之事件监听机制(上)

[复制链接]
云韵 发表于 2020-12-31 18:14:08 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
文章目录



  一、Spring对事件监听的处理

1. 初始化事件管理器

Spring容器启动过程中,调用了initApplicationEventMulticaster方法,从方法的定名上面可以看出是初始化事件管理器,那么Spring详细是怎么操纵的呢?
  1. ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (beanFactory.containsLocalBean("applicationEventMulticaster")) {        ......} else {        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);        beanFactory.registerSingleton("applicationEventMulticaster",this.applicationEventMulticaster);}
复制代码
如果我们没有自界说id为applicationEventMulticaster的bean,那么Spring默认实现了SimpleApplicationEventMulticaster,并把事件管理器注册到单例缓存中。
2.注册事件监听

  1. String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}
复制代码
遍历bean工厂中所有的bean,将实现了ApplicationListener接口的bean的bean标识,注册到ApplicationEventMulticaster中。
  1. this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
复制代码
ListenerRetriever是界说在抽象类AbstractApplicationEventMulticaster中的一组特定目标监听器的帮助类,它的实例作为事件管理器的成员,用来生存所有事件监听器及其bean标识。
3.发布事件

  1. getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
复制代码
Spring容器启动过程中,会在上文实例化过的事件管理器中发布事件
  1. for (ApplicationListener listener : getApplicationListeners(event, type)) {        invokeListener(listener, event);}
复制代码
Spring在发布事件中,总共做了两件事:
  1. - 获取所有监听该发布事件的监听类- 循环调用监听类的监听方法
复制代码
这里值得注意的是,遍历出来的监听器需要与事件范例以及事件源举行匹配,只有匹配乐成,才会触发监听,这里详细如何举行匹配的呢,请看下面

从该方法的注释上也能看出来该方法的作用:确定给定的监听器是否支持给定的事件(将监听器包装成GenericApplicationListener,因为该接口界说了supportsEventType和supportsSourceType方法,可以判定监听器是否支持传入的事件范例和事件源范例)。
4. 监听类实例化

通过前面三个步调,Spring的事件监听根本上整体架构已经出来了,但是总感觉缺了点什么,步调二注册事件监听的时候,只是将事件监听的bean标识注册到事件管理器中,但是bean是什么时候举行实例化的呢。
在启动容器的refresh方法中,在初始化事件管理器之前,调用了prepareBeanFactory(beanFactory),在该方法中注册了事件监听探测器的组件,负责将探测到的事件监听器bean注册到事件发布器中。
  1. // Register early post-processor for detecting inner beans as ApplicationListeners.beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
复制代码
5.监听事件


Spring的抽象类ApplicationEvent下面有四个抽象子类


  • ContextCloseEvent(容器关闭)
  • ContextRefreshedEvent(容器刷新)
  • ContextStoppedEvent(容器停止)
  • ContextStartedEvent(容器启动)
这四个事件都是Spring默认提供给我们的,它们都继承了ApplicationEvent,我们也可以通过继承ApplicationEvent自界说事件。
   二、Spring事件监听实战

1.需求

在订单服务中,用户下单乐成后,需要物流服务和库存服务举行相应的处理,接纳异步解耦的方式。
2.编码


  • 实例化一个上下文对象,启动Spring容器,代表订单服务运行
  1. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");System.out.println(Thread.currentThread().getName() + ":订单服务开始运行……");System.out.println(Thread.currentThread().getName() + ":创建订单完成,通知物流、库存……");
复制代码

  • 创建一个订单事件
  1. public class OrderEvent extends ApplicationEvent {    public OrderEvent(Object source) {        super(source);    }}
复制代码

  • 创建一个物流监听器监听订单事件
  1. @Componentpublic class LogisticsListener implements ApplicationListener {    @Override    public void onApplicationEvent(OrderEvent orderEvent) {        System.out.println(Thread.currentThread().getName() + ":物流服务开始工作……");    }}
复制代码

  • 创建一个库存监听器监听订单事件
  1. @Componentpublic class StoreListener implements ApplicationListener {    @Override    public void onApplicationEvent(OrderEvent orderEvent) {        System.out.println(Thread.currentThread().getName() + ":库存服务开始工作……");    }}
复制代码

  • 在订单服务中发布订单事件,所有监听该事件的监听器都能收到消息
  1. @Testpublic void test2() {    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");    System.out.println(Thread.currentThread().getName() + ":订单服务开始运行……");    System.out.println(Thread.currentThread().getName() + ":创建订单完成,通知物流、库存……");    context.publishEvent(new OrderEvent(this));}
复制代码
效果:
  main:订单服务开始运行……
main:创建订单完成,通知物流、库存……
main:物流服务开始工作……
main:库存服务开始工作……
3.思考

通过上面的编码,我们分开了订单服务、物流服务和库存服务,它们之间相互独立,但从效果中来分析,它们都是在主线程中运行的,说明没有实现真正的异步,到这里自然我们会想到使用多线程举行处理,那么Spring有没有提供这方面的支持呢?
4.线程池与事件监听


Spring在调用监听事件之前,会判定事件监听是否存在线程池,如果有则交由线程池处理。

  • 配置线程池taskExecutor
  1.                                                
复制代码

  • 在监听方法上面加入@Async注解,表明该方法是异步的
效果:
  main:订单服务开始运行……
main:创建订单完成,通知物流、库存……
myTaskExecutor1:物流服务开始工作……
myTaskExecutor2:库存服务开始工作……
  Spring源码之事件监听机制(下)

来源:https://blog.csdn.net/qq_27023083/article/details/111772935
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

发布主题

专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )