上一篇我们在Spring源码十一:事件驱动中,介绍了spring refresh方法的initMessageSource方法与initApplicationEventMulticaster方法,举了一个简单的例子进行简单的使用的Spring为我们提供的事件驱动发布的示例。这一篇我们将继续跟踪源码,看看Spring事件是如何发布的。
事件是如何发布的呢?
{
public static void main(String[] args) {
ApplicationContext context = new MyselfClassPathXmlApplicationContext("applicationContext.xml");
// JmUser jmUser = (JmUser)context.getBean("jmUser");
// System.out.println(jmUser.getName());
// System.out.println(jmUser.getAge());
// 发布事件
MyselfEvent event = new MyselfEvent("事件源:source", "This is a custom event");
context.publishEvent(event);
}
}
今天我们先从refresh方法中暂时抽离出来,接着上一篇我们给的示例往下看:
我们以MyselfClassPathXmlApplicationContext(继承ClassPathXmlApplicationContext
类)中的publishEvent方法作为入口,看下事件MyselfEvent是如何发布的呢:
我们继续进入重载的publishEvent方法中:
/**
*
* Publish the given event to all listeners.
* 用于将指定的事件发布给所有监听器
* @param event the event to publish (may be an {@link ApplicationEvent}
* 参数表示要发布的事件,可以是 ApplicationEvent
* or a payload object to be turned into a {@link PayloadApplicationEvent})
* 或一个负载对象(将被转换为 PayloadApplicationEvent)。
* *
* @param eventType the resolved event type, if known
* @since 4.2
*/
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
// 判断传入的 event 是否为 ApplicationEvent 的实例:
// 如果是,则直接赋值给 applicationEvent。
// 如果不是,则将其包装为 PayloadApplicationEvent。
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
// 如果 eventType 为空且事件被包装为 PayloadApplicationEvent,则从包装的事件中获取事件类型
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// 事件分发
// Multicast right now if possible - or lazily once the multicaster is initialized:
// 判断 earlyApplicationEvents 是否不为空
// 如果不为空,说明广播器还未初始化,则将事件添加到 earlyApplicationEvents 队列中,等待广播器初始化后再分发。
// 如果为空,说明广播器已初始化, 立即分发事件。
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// 直接通过 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
// 如果当前上下文有父上下文 (this.parent 不为空),则同样向父上下文发布事件:
if (this.parent != null) {
//如果父上下文是 AbstractApplicationContext 的实例,则调用其 publishEvent 方法,同时传递事件和事件类型。
// 如果不是,则直接调用父上下文的 publishEvent 方法。
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
上述代码注释已经很清晰了,我们简单总结下:这段代码的主要功能是将事件发布给所有注册的监听器,并在可能的情况下向父上下文传递事件。它首先确保事件对象不为空,然后检查和包装事件,最后通过事件广播器将事件分发给监听器。如果广播器未初始化,则将事件暂时存储,等待初始化后再分发。
根据我们我们示例代码,可以发现我们传入的event类型肯定是AppellationEvent的实例,毕竟MyselfEvent就是继承ApplicationEvent接口的。接着我们进入get ApplicationEventMulticaster.multicastEvent(),其中event我们已经分析过了:
ApplicationEventMulticaster
getApplicationEventMulticaster()方法获取的对象默认的是SimpleApplicationEventMulticast类:
继续进入:
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
// 确定事件类型,如果传入的 eventType 不为空,则使用它;否则,使用默认的事件类型
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 获取任务执行器,如果没有设置,则为 null
Executor executor = getTaskExecutor();
// 遍历所有匹配的监听器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
// 如果任务执行器不为空,则使用它异步执行监听器
executor.execute(() -> invokeListener(listener, event));
}
else {
// 如果任务执行器为空,则同步调用监听器
invokeListener(listener, event);
}
}
}
如上图:
在方法multicastEvent中默认是没有设置线程池的,所以executor为空。接着往下看:
我们看到会通过getApplicationListeners方法获取Spring容器中的所有监听器,然后依次遍历处理这些监听器,从这里我们初步可以知道:
广播器的作用其实就是当一个事件发生时,通知Spring容器中的所有注册的监听器,然后让每个监听器自行决定是否要处理这个事件。
/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
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);
}
}
如上图所示:最终就会调用监听器中的onApplicationEvent方法执行监听器中的逻辑。
目前只有我们自定义的监听器才会处理事件MyselfEvent,所以其他的监听器就算执行了onApplicationEvent方法,也会选择无视这个事件。
看下调用栈:
主要就是通过广播器ApplicationEventMulticaster和监听器ApplicationListener来实现的,大家也可以理解为是发布-订阅模式,ApplicationEventMulticaster用来广播发布事件,ApplicationListener监听订阅事件,每种监听器负责处理一种或多种事件:我们自定义的监听器因为指定了泛型,所以,只能处理指定类型的事件,稍微修改一下如下代码所示:
package org.springframework.listener;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.event.MyselfEvent;
import org.springframework.stereotype.Component;
/**
* 自定义监听
*/
@Component
public class MyselfCommonListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
// 处理事件
if (event instanceof MyselfEvent ){
MyselfEvent event1 = (MyselfEvent) event;
event1.event();
System.out.println("监听接受事件");
System.out.println("Received event with message: " + event1.getMessage());
}
}
}
而且,如果大家冷静分析一下会发现,其实Spring这套发布订阅的模式,采用的就是设计模式中的观察者模式,ApplicationEventMulticaster作为广播事件的subject,属于被观察者,ApplicationListener作为Observer观察者,最终是用来处理相应的事件的。
注册ApplicationListener
上一节咱们跳出了refresh方法,今天咱们继续回到refresh方法中:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing. 1、初始化上下文信息,替换占位符、必要参数的校验
prepareRefresh();
// Tell the subclass to refresh the internal bean factory. 2、解析类Xml、初始化BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 这一步主要是对初级容器的基础设计
// Prepare the bean factory for use in this context. 3、准备BeanFactory内容:
prepareBeanFactory(beanFactory); // 对beanFactory容器的功能的扩展:
try {
// Allows post-processing of the bean factory in context subclasses. 4、扩展点加一:空实现,主要用于处理特殊Bean的后置处理器
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context. 5、spring bean容器的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation. 6、注册bean的后置处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context. 7、初始化消息源
initMessageSource();
// Initialize event multicaster for this context. 8、初始化事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses. 9、扩展点加一:空实现;主要是在实例化之前做些bean初始化扩展
onRefresh();
// Check for listener beans and register them. 10、初始化监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons. 11、实例化:非兰加载Bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event. 12、发布相应的事件通知
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
/**
* Add beans that implement ApplicationListener as listeners.
* Doesn't affect other listeners, which can be added without being beans.
*/
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!
// 获取所有ApplicationListener类型监听器注册到广播器中
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);
}
}
}
上述内容可以看到这里就是将各种监听器注册到广播器中,然后通过广播器通知各个监听器,监听器自行处理事件。