文章目录
一、Spring对事件监听的处理
1. 初始化事件管理器
Spring容器启动过程中,调用了initApplicationEventMulticaster方法,从方法的定名上面可以看出是初始化事件管理器,那么Spring详细是怎么操纵的呢?
- ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (beanFactory.containsLocalBean("applicationEventMulticaster")) { ......} else { this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton("applicationEventMulticaster",this.applicationEventMulticaster);}
复制代码 如果我们没有自界说id为applicationEventMulticaster的bean,那么Spring默认实现了SimpleApplicationEventMulticaster,并把事件管理器注册到单例缓存中。
2.注册事件监听
- String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}
复制代码 遍历bean工厂中所有的bean,将实现了ApplicationListener接口的bean的bean标识,注册到ApplicationEventMulticaster中。
- this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
复制代码 ListenerRetriever是界说在抽象类AbstractApplicationEventMulticaster中的一组特定目标监听器的帮助类,它的实例作为事件管理器的成员,用来生存所有事件监听器及其bean标识。
3.发布事件
- getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
复制代码 Spring容器启动过程中,会在上文实例化过的事件管理器中发布事件
- for (ApplicationListener listener : getApplicationListeners(event, type)) { invokeListener(listener, event);}
复制代码 Spring在发布事件中,总共做了两件事:
- - 获取所有监听该发布事件的监听类- 循环调用监听类的监听方法
复制代码 这里值得注意的是,遍历出来的监听器需要与事件范例以及事件源举行匹配,只有匹配乐成,才会触发监听,这里详细如何举行匹配的呢,请看下面
从该方法的注释上也能看出来该方法的作用:确定给定的监听器是否支持给定的事件(将监听器包装成GenericApplicationListener,因为该接口界说了supportsEventType和supportsSourceType方法,可以判定监听器是否支持传入的事件范例和事件源范例)。
4. 监听类实例化
通过前面三个步调,Spring的事件监听根本上整体架构已经出来了,但是总感觉缺了点什么,步调二注册事件监听的时候,只是将事件监听的bean标识注册到事件管理器中,但是bean是什么时候举行实例化的呢。
在启动容器的refresh方法中,在初始化事件管理器之前,调用了prepareBeanFactory(beanFactory),在该方法中注册了事件监听探测器的组件,负责将探测到的事件监听器bean注册到事件发布器中。
- // 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容器,代表订单服务运行
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");System.out.println(Thread.currentThread().getName() + ":订单服务开始运行……");System.out.println(Thread.currentThread().getName() + ":创建订单完成,通知物流、库存……");
复制代码- public class OrderEvent extends ApplicationEvent { public OrderEvent(Object source) { super(source); }}
复制代码- @Componentpublic class LogisticsListener implements ApplicationListener { @Override public void onApplicationEvent(OrderEvent orderEvent) { System.out.println(Thread.currentThread().getName() + ":物流服务开始工作……"); }}
复制代码- @Componentpublic class StoreListener implements ApplicationListener { @Override public void onApplicationEvent(OrderEvent orderEvent) { System.out.println(Thread.currentThread().getName() + ":库存服务开始工作……"); }}
复制代码
- 在订单服务中发布订单事件,所有监听该事件的监听器都能收到消息
- @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在调用监听事件之前,会判定事件监听是否存在线程池,如果有则交由线程池处理。
- 在监听方法上面加入@Async注解,表明该方法是异步的
效果:
main:订单服务开始运行……
main:创建订单完成,通知物流、库存……
myTaskExecutor1:物流服务开始工作……
myTaskExecutor2:库存服务开始工作……
Spring源码之事件监听机制(下)
来源:https://blog.csdn.net/qq_27023083/article/details/111772935
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |