发布事件的源代码所在处
public void publishEvent(ApplicationEvent event) {
Assert.notNull(event, "Event must not be null");
if (this.logger.isTraceEnabled()) {
this.logger.trace("Publishing event in " + this.getDisplayName() + ": " + event);
}
this.getApplicationEventMulticaster().multicastEvent(event);
if (this.parent != null) {
this.parent.publishEvent(event);
}
}
Spring父子容器发布事件调用都是这段代码
父容器finishRefresh时发布事件this.parent == null,会调用一次
子容器finishRefresh时发布事件this.parent != null,会调用两次
所以一个事件监听器会被调用三次,必要时我们需要对自己对监听器做幂等,防止重复调用引发bug!!!
例如,加以下判断只允许父容器调用一次:
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if(event.getApplicationContext().getDisplayName().equals("Root WebApplicationContext")){
// 监听器逻辑
}
}
/* 上下文更新事件(ContextRefreshedEvent):该事件会在ApplicationContext被初始化或者更新时发布。也可以在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。 上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。 上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。 上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。 请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。 */