这是继《springboot事件监听机制一:实战应用》第二篇,知其然,当然还要知其所以然,深入的源码里面探寻一下这一有套机制的工作原理。spring生态很茂盛,这里不会站太高去分析这个问题,大扯spring的一些原理,而是以一个求知者的心态去探索spring监听机制的秘密,可能我分析得并不透彻,但我想如果能给看到这篇文章的你带去一些灵感或者触动也是好的。罗马不是一天就能建立起来的,想要弄懂它也非一天的事,多想多看总会明白的。另外看源码的时候,一定是带着问题去探寻,时刻把握好问题的核心,切忌被旁枝末节打扰而迷失的源码里了(如果对一旁枝末节实在很感兴趣,可以先记录下来位置,之后再来探寻)。发现问题,然后解决问题,这就是进步!现在一起来进步吧!
springboot事件监听机制的原理是观察者模式,观察者模式有几个核心的元素:
正如上一篇文章中的示例,把各业务中的短信发送需求抽象成一个短信发事件,在各业务需要发送短信的时候,就通过事件发布器来发布事件,然后触发短信发送监听器里的发送短信操作一样,Spring生态这么庞大,功能也多,自身的事件自不会少,如容器启动、容器刷新、关闭、停止等都是一个事件。为什么会这样呢?这是因为Spring容器在初始化、启动、刷新、关闭等这些过程中,也需要通知其他模块,所以spring自身也有很多事件也就不奇怪了。 但是这么多事件,功能不一样,但是本质是相同的,所有事件一基类都是java.util.EventObject。所以下面还是以上一篇文章中的短信发布事件作为例子,来探寻一下springboot的事件监听的工作原理。
在上一篇的例子中,封装好短信事件,同是也把短信监听器通过@component注解注册到了spring容器里,然后就在业务中直接通过事件发布器(ApplicationEventPublisher)发布了,这中间许多细节是什么样的呢?比如:
事件发布器实例化的入口org.springframework.context.support.AbstractApplicationContext#refresh中调用了org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster,最后实际会实例出一个SimpleApplicationEventMulticaster对象,这个对象一般都翻译成事件广播器,他的作用就是发布事件、接受监听器的注册、回调监听器中的回调方法。眼尖的人都看出来了,在业务类里注册的事件发布器是ApplicationEventPublisher,不是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 {//spring容器启动的时候,applicationEventMulticaster还没有创立,会走这里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() + "]");}}
}
事件监听器注册到事件发布器里的逻辑在这个方法:org.springframework.context.support.AbstractApplicationContext#registerListeners,而registerListeners()也是在org.springframework.context.support.AbstractApplicationContext#refresh()里被调用的
protected void registerListeners() {// Register statically specified listeners first.for (ApplicationListener> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}//smsListener通过@Component注册到spring容器里后,在这里注册到spring的事件广播器里String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}Set earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}
}
顺着com.example.springeventdemo.service.UserService#registe()里的this.applicationEventPublisher.publishEvent(),使劲往里面找,最后找到了org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object),到这感觉出来点啥没,所有的逻辑都指向AbstractApplicationContext类,这里先按下不表,继续往下找事件是发布到哪了,最后在org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)里找到了一句 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType),顺着getApplicationEventMulticaster(),再往下找到spring的事件广播器接口ApplicationEventMulticaster,SimpleApplicationEventMulticaster是ApplicationEventMulticaster接口的实现类,这下明白在第一个问题中疑问了吧,表面上的事件发布器是ApplicationEventPublisher,而实际最终执行发布事件的是SimpleApplicationEventMulticaster。
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);}}
}
到这里,只是找到了通过this.applicationEventPublisher.publishEvent()找到了发布事件的实际干活人(SimpleApplicationEventMulticaster),它是怎么干活的呢?
沉住气,继续向里面翻org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)后,仔细看一下里面的逻辑:先看一下有没有线程池可用,如果有,就用,如果没有,就不用,直接执行监听器里的回调方法onApplicationEvent(),最后找到了SmsListener中具体执行发短信操作的onApplicationEvent();
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);}}
}
Spring事件的发布器的实例化、Spring事件监听器注册到事件发布器、Spring事件的发布都指向一个类AbstractApplicationContext,其中Spring事件的发布器的实例化、Spring事件监听器注册到事件发布器都是在org.springframework.context.support.AbstractApplicationContext#refresh()里完成,了解spring bean的生命周期的小伙伴,对这个方法肯定不陌生,这可是spring容器启动的灵魂,因此玩好spring,bean的生命周期必须玩透。到这里spring事件监听机制的工作原理基本摸清楚了,很多关键的事情,如事件发布器的实例化、事件监听器的注册这些都在spring容器启动的时候就开始了。这些关系理清楚后,才突然发现:真的是大道至简,牛逼就是简单,简单就是牛逼,致敬spring!