前言
陆续阅读了Spring Boot源码中,有不少地方都用到了监听器。每次看到监听器的代码都一头雾水,不懂其中的设计理念,这次决定肝一篇监听器的博文。
一、监听器
1.概述
何为监听器?就是用来监听程序执行的。监听器可以做什么事?可以监听程序执行,使程序在不同的阶段做不同的事情,并且与程序主业务逻辑解耦。
那么读者读完是否很迷茫?如果学过MQ的可以把想象成一种订阅-发布模式,监听器首先订阅事件,然后其它功能主动发布事件,已触发监听器订阅的事件。
举个例子
:最常见的购物逻辑中,下订单以后就要扣库存,可以理解为扣库存这个操作监听了订单,这就是一种监听器,当下了订单,此时触发监听器,执行扣库存操作。有没有觉得监听器更像是订阅-发布模式
可能读完这个例子,大家觉得很难理解,这种下订单、扣库存,我在代码里面按照逻辑依次写下去不就完了,为啥要整的这么麻烦?
个人理解
:Spring提供的监听器,其实是一种设计模式,目的是为了更好的扩展性,例如像上面的下订单扣库存,肯定代码直接写最省事,但这样就耦合度高了,其它的业务功能都这样写嘛?如果Spring按照这种方式写,那么想扩展功能就只剩改源码了
所以从整体设计的角度,Spring框架为了提供更好的扩展性,采用了观察者模式,设计出了这么一套监听器,以供使用。这样开发人员不仅可以扩展Spring的监听器,也可以自定义新的监听器,一举两得。这样得以让代码更加优雅,便于扩展
2.组成
Spring的监听器由以下3部分组成:
事件(ApplicationEvent)
:要广播,发送的消息. 监听器监听的事情监听器(ApplicationListener)
: 观察者模式中的观察者, 监听器监听特定事件, 并在内部定义了事件发生后的相应逻辑.事件发布器(ApplicationEventMulticaster)
:对应于观察者模式中的被观察者/主题.负责通知观察者. 对外提供发布事件和增删事件监听器的接口.维护事件和事件监听器之间的关系.并在事件发生时负责通知事件监听器.
可能看到这3个词觉得很难理解,那么换一种解释:
事件
:负责调用逻辑,对应订阅-发布中的订阅监听器
:负责执行逻辑,也就是你的自定义逻辑事件发布器
:负责根据事件类型去调用你的自定义逻辑,底层就是一个循环,根据你传过来的事件类型,遍历调用对应的监听器
3.Hello World
上面介绍到的例子:下单后减库存. 减库存就是一个事件, 这个事件需要一个事件播放器, 将事件播放出去. 然后另一端事件监听器, 接收到信息,进行处理。简单写一下
【第1步
:创建一个订单实体类】
@Data
public class Order {private String id;private String name;}
【第2步
:创建一个事件
,继承ApplicationEvent
】
// 继承ApplicationEvent必须重写构造方法
public class OrderEvent extends ApplicationEvent {// 一般在调用的时候会把this传进来,也就是当前类public OrderEvent(Object source) {super(source);}// 可以在this的基础上,继续增加所需的参数public OrderEvent(Object source, Order order) {super(source);System.out.println("创建了事件-----");}}
【第3步
:创建监听器
,实现ApplicationListener
】
@Component
public class OrderEventListener implements ApplicationListener<OrderEvent> {@Overridepublic void onApplicationEvent(OrderEvent event) {// 参数event可以接收传过来的参数,一般就是上一步逻辑处理的结果,也可以不传System.out.println("触发了事件----------");}}
【第4步
:启动类】
@Configuration
@ComponentScan
public class TestMain {@Testpublic void m1() {// 1.创建IOC容器AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TestMain.class);// 2.创建订单Order order = new Order();order.setId("订单号:i4u1212412312");order.setName("商品名称:T恤");System.out.println("订单创建完毕---" + order);// 3.发布事件, 这里会借助事件分发器去调用监听器ctx.publishEvent(new OrderEvent(this, order));System.out.println("结束了-------");}}
写完以后,仔细思考一下,就会发现其实就是A调用B,但是Spring把A叫做事件,B叫做监听器,然后调用由事件分发器执行,解耦合
4.分类
上面简单介绍了监听器,那么监听器有哪些呢?两种类型:一种是内置监听器, 一种是自定义监听器
1) 内置监听器
Spring定义了一个内置监听器的父类ApplicationContextEvent
,实现该类的就是内置监听器
一共有4类实现了ApplicationContextEvent
Event | 说明 |
---|---|
ContextRefreshEvent | 当容器被实例化或者refresh时发布.如调用refresh()方法. 此处的实例化是指所有的bean都已被加载,后置处理器都被激活,所有单例bean都已被实例化,所有的容器对象都已经准备好可使用. 如果容器支持热重载,则refresh()可以被触发多次(XmlWebApplicationContext支持热刷新, 而GenericApplicationContext不支持热刷新) |
ContextStartedEvent | 当容器启动时发布, 即调用start()方法, 已启用意味着所有的lifecycle都已显示收到了start的信号 |
ContextStoppedEvent | 当容器停止时发布. 即调用stop()方法, 既所有的lifecycle bean都已显示接收了stop信号, 关闭的容器可以通过start()方法重启 |
ContextClosedEvent | 当容器关闭时发布. 即调用close()方法, 关闭意味着所有的单例bean都已被销毁. 关闭的容器不能被重启或refresh() |
总结
:这些内置监听器事件是Spring框架自己使用的,以供扩展Spring源码可以使用,例如:我想在Spring初始化完成以后执行某个操作,可以自定义监听器类,监听ContextRefreshEvent
事件,然后执行自定义逻辑
在简单点说,这些是Spring框架初始化默认发布的事件,无法更改事件,但你可以监听执行自定义逻辑,当然也可以自定义事件
【举个例子
】可以直接创建一个自定义监听器,监听ContextRefreshedEvent
事件,这样当Spring容器初始化完成,就会执行这个监听器的逻辑
@Component
public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {private String name = "qqweqwe123";@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {System.out.println("所有的bean初始化完成了");}
}
2) 自定义监听器
自定义监听器,其实上面的例子已经写过1遍了,那么这里介绍一下实现的2种方式:
【方式1
:基于接口】
@Component
public class HelloEventListener implements ApplicationListener<OrderEvent> {@Overridepublic void onApplicationEvent(OrderEvent event) {if (event.getName().equals("减库存")) {System.out.println("减库存....");}}
}
【方式2
:基于注解】
@Component
public class OrderEventListener {@EventListener(OrderEvent.class)public void onApplicationEvent(OrderEvent event) {if (event.getName().equals("减库存")) {System.out.println("减库存....");}}
}
二、源码分析
1.初始化
监听器的初始化,都是在refresh()
中,那么下面就来看一下,跟监听器有关的类:
1) initApplicationEventMulticaster()
初始化一个监听器多播器,默认是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 {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) registerListeners()
注册监听器,来源分为3步:
- 静态指定的。也就是
META-INF/spring.factories
中配置的 - 容器中获取。包括:引入其它依赖携带的监听器 + 自定义开发的监听器
- 把早期的监听器给注入进来,很少用到
protected void registerListeners() {// Register statically specified listeners first.for (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let post-processors apply to them!String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}// Publish early application events now that we finally have a multicaster...Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (earlyEventsToProcess != null) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}
}
3) finishRefresh()
protected void finishRefresh() {// Clear context-level resource caches (such as ASM metadata from scanning).clearResourceCaches();// Initialize lifecycle processor for this context.initLifecycleProcessor();// Propagate refresh to lifecycle processor first.getLifecycleProcessor().onRefresh();// Publish the final event.// 发布一个事件publishEvent(new ContextRefreshedEvent(this));// Participate in LiveBeansView MBean, if active.LiveBeansView.registerApplicationContext(this);
}
4) 总结
经过以上3步,首先事件发布器有了,默认SimpleApplicationEventMulticaster
,监听器有了,已经注入进去了,剩下的就是通过事件发布器
,来触发监听器
2.发布
初始化完毕以后,接下来就是使用了,当发布事件的时候,如何执行呢?
先说原理
:通过publishEvent()
发布事件以后,底层就会根据事件类型,循环判断所有的监听器,找到符合类型的,然后执行。
1) publishEvent() 入口
事件发布,然后交由时间发布器
执行
// AbstractApplicationContext.java@Override
public void publishEvent(ApplicationEvent event) {publishEvent(event, null);
}protected void publishEvent(Object event, @Nullable ResolvableType eventType) {Assert.notNull(event, "Event must not be null");// Decorate event as an ApplicationEvent if necessaryApplicationEvent 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 initializedif (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);}}
}
2) 发布事件
获取到匹配的监听器,然后循环执行
// SimpleApplicationEventMulticaster.java@Override
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) 获取匹配的监听器
从全部的监听器中,遍历循环,找到支持该事件的监听器,这里代码只展示了大概,具体没有展开,大体就是一个for循环+if判断
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {Object source = event.getSource();Class<?> sourceType = (source != null ? source.getClass() : null);ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);// Quick check for existing entry on ConcurrentHashMap...ListenerRetriever retriever = this.retrieverCache.get(cacheKey);if (retriever != null) {return retriever.getApplicationListeners();}if (this.beanClassLoader == null ||(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {// Fully synchronized building and caching of a ListenerRetrieversynchronized (this.retrievalMutex) {retriever = this.retrieverCache.get(cacheKey);if (retriever != null) {return retriever.getApplicationListeners();}retriever = new ListenerRetriever(true);// 【这里会循环所有的监听器,根据 supportsEventType() 来判断是否支持该事件类型】Collection<ApplicationListener<?>> listeners =retrieveApplicationListeners(eventType, sourceType, retriever);this.retrieverCache.put(cacheKey, retriever);return listeners;}}else {// No ListenerRetriever caching -> no synchronization necessaryreturn retrieveApplicationListeners(eventType, sourceType, null);}
}
4) 执行监听器
接下来就是执行监听器了,看到invoke就知道了,反射调用对应的方法即可
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {ErrorHandler errorHandler = getErrorHandler();if (errorHandler != null) {try {doInvokeListener(listener, event);}catch (Throwable err) {errorHandler.handleError(err);}}else {// 【执行】doInvokeListener(listener, event);}
}
接下来就是执行监听器了,看到invoke就知道了,反射调用对应的方法即可
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {ErrorHandler errorHandler = getErrorHandler();if (errorHandler != null) {try {doInvokeListener(listener, event);}catch (Throwable err) {errorHandler.handleError(err);}}else {// 【执行】doInvokeListener(listener, event);}
}