Spring事件被三次调用剖析-ApplicationListener

发布事件的源代码所在处

org.springframework.context.support.AbstractApplicationContext#publishEvent

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父子容器发布事件调用都是这段代码

  1. 父容器finishRefresh时发布事件this.parent == null,会调用一次
  2. 子容器finishRefresh时发布事件this.parent != null,会调用两次

所以一个事件监听器会被调用三次,必要时我们需要对自己对监听器做幂等,防止重复调用引发bug!!!
例如,加以下判断只允许父容器调用一次:

@Override  
public void onApplicationEvent(ContextRefreshedEvent event) {
    if(event.getApplicationContext().getDisplayName().equals("Root WebApplicationContext")){
        // 监听器逻辑
    }
}

附录:
Spring 提供了以下5中标准的事件:

  • 上下文更新事件(ContextRefreshedEvent):该事件会在ApplicationContext被初始化或者更新时发布。也可以在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
  • 上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
  • 上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
  • 上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。
  • 请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值