SpringBoot版本:2.0.2.RELEASE
SpringFramework版本:5.0.6.RELEASE
谁是SpringFramework的事件发布器
从UML图看,ApplicationEventPublisher只声明了发布事件的方法,到了ConfigurableApplicationContext才补充了与监听器关联的方法。这些方法最终由AbstractApplicationContext实现。而它的子类一般也没有重载这些方法。因此,从类定义的角度来看,AbstractApplicationContext承担了发布事件的责任。
那么在一个SpringBoot工程里,它是如何成为事件发布者呢?在前文多处已经暗示,有一个发布器移交的这么一个过程,详见EventPublishingRunListener的各发布事件方法。
在SpringApplication#run方法的整体过程控制下,在SpringBoot发布ApplicationPreparedEvent事件的时候,有个将SpringBoot自己的Listener添加到ConfigurableApplicationContext的动作。然后AbstractApplicationContext#refresh方法会被调用,在该方法里完成了加载SpringFramework的监听器和初始化了SpringFramework层面的事件发布器SimpleApplicationEventMulticaster,最后调用finishRefresh方法发布ContextRefreshedEvent事件。下面列出AbstractApplicationContext#refresh方法内重点函数:
@Override
public void refresh() throws BeansException, IllegalStateException {
....
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
....
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
....
// Check for listener beans and register them.
registerListeners();
....
// Last step: publish corresponding event.
finishRefresh();
}
这些函数不难,读者可自行翻阅。但有一点要注意的整个SpringBoot启动过程中,事件发布的顺序,以及在发布各个事件的时候系统为此做了什么准备工作。控制着这些节奏的其实是SpringApplication,在它的run方法里已经编好了整个大纲。
双子座的消息发布者
在《SpringBoot事件与监听机制》已经知道SpringBoot的事件发布器是EventPublishingRunListener,而它最终是委托SimpleApplicationEventMulticaster的来完成事件的发布。
在EventPublishingRunListener#contextLoaded方法看到为发点布器交棒的准备,在started和running方法,已经看到发布事件的工作交给了ConfigurableApplicationContext去完成。我们回头看contextLoaded方法,只是将SpringBoot的监听器添加到ConfigurableApplicationContext,但并没有将自己的SimpleApplicationEventMulticaster交过去,那么ConfigurableApplicationContext是用什么来发布信息呢?
在AbstractApplicationContext里我们看到ApplicationEventMulticaster接口类型属性的声明:
/** Helper class used in event publishing */
@Nullable
private ApplicationEventMulticaster applicationEventMulticaster;
在AbstractApplicationContext#refresh方法里会调用initApplicationEventMulticaster函数,里面就对该变量进行赋值:
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.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
就是说,AbstractApplicationContext也有一个SimpleApplicationEventMulticaster作为自己的属性,名字叫applicationEventMulticaster。
我们再来观察AbstractApplicationContext是如何发布事件的,我们从publishEvent(ApplicationEvent event)方法开始跟踪,然后会来到publishEvent(Object event, @Nullable ResolvableType eventType)方法:
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
....
if (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);
}
}
}
getApplicationEventMulticaster方法如下:
ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
if (this.applicationEventMulticaster == null) {
throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
"call 'refresh' before multicasting events via the context: " + this);
}
return this.applicationEventMulticaster;
}
到这里就明白了,SpringFramwork最终也是用SimpleApplicationEventMulticaster来发布事件,但此SimpleApplicationEventMulticaster并不是SpringBoot的SimpleApplicationEventMulticaster。那么这样的话会产生什么效果呢?前文已多次讲到在AbstractApplicationContext#refresh方法执行前,在EventPublishingRunListener#contextLoaded方法里已经将SpringBoot监听器添加给ConfigurableApplicationContext(即AbstractApplicationContext),所以后续SpringBoot委托AbstractApplicationContext发布的任何事件,SpringBoot的监听器都有可能会收到(“有可能”是因为还有事件类型以及事件源类型匹配的问题在里面)。
从EventPublishingRunListener各发布事件的方法看来,SpringBoot层面的SimpleApplicationEventMulticaster只是起到临时发布事件的作用,在ConfigurableApplicationContext未完成refresh前,SpringBoot启动经历的各状态先由SpringBoot层面的SimpleApplicationEventMulticaster发布事件。当ConfigurableApplicationContext完成refresh后,就交由它去完成发布事件的工作。那么为什么SpringBoot不把自己的EventPublishingRunListener传给ConfigurableApplicationContext呢?其实在SpringBoot1.x版本里确实是这样做的,到了2.x版本就调整成现在这样。为什么有这个调整,我猜SpringBoot毕竟是基于Spri