spring事件机制-onApplicationEvent执行两次

本文介绍了Spring事件机制中onApplicationEvent方法被执行两次的案例复现,详细分析了原因——在Web项目中由于存在父子容器导致事件重复发布。并提供了针对性的解决方案,通过使用父容器来发送事件,确保只触发一次。测试结果显示问题已成功解决。

一、case复现

事件定义

 

Java代码  收藏代码
  1. public class MyEvent extends ApplicationEvent {  
  2.   
  3.     public MyEvent(Object object) {  
  4.         super(object);  
  5.     }  
  6. }  

 

 

监听定义

 

Java代码  收藏代码
  1. @Component  
  2. public class MyListener implements ApplicationListener<MyEvent> {  
  3.   
  4.     @Override  
  5.     public void onApplicationEvent(MyEvent event) {  
  6.         System.out.println("myEvent occured msg : " + event.getSource());  
  7.     }  
  8. }  

 

 

事件通知

 

Java代码  收藏代码
  1. @ResponseBody  
  2. @RequestMapping(value = "/publish")  
  3. public String publish(String key) {  
  4.      BeanFactory.pushEvent(new MyEvent("publish"));  
  5.      return "success";  
  6. }  

 

 

 

Java代码  收藏代码
  1. @Component  
  2. public class BeanFactory implements ApplicationContextAware {  
  3.   
  4.     private static ApplicationContext applicationContext;  
  5.   
  6.     public static <T> T getBean(String beanName, Class<T> clazz) {  
  7.         return (T) applicationContext.getBean(beanName);  
  8.     }  
  9.   
  10.     /** 
  11.      * 通知事件 
  12.      * 
  13.      * @param applicationEvent 
  14.      */  
  15.     public static void pushEvent(ApplicationEvent applicationEvent) {  
  16.         //获取父容器发送事件  
  17.         //ContextLoader.getCurrentWebApplicationContext().publishEvent(applicationEvent);  
  18.         applicationContext.publishEvent(applicationEvent);  
  19.     }  
  20.   
  21.     @Override  
  22.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
  23.         this.applicationContext = applicationContext;  
  24.     }  
  25.   
  26.     public static ApplicationContext getApplicationContext() {  
  27.         return applicationContext;  
  28.     }  
  29. }  

 测试结果:

 

Java代码  收藏代码
  1. myEvent occured msg : publish  
  2. myEvent occured msg : publish  

 

 

三、原因

在web项目中如果同时集成了spring和springMVC的话,上下文中会存在两个容器,即spring的applicationContext.xml的父容器和springMVC的applicationContext-mvc.xml的子容器。

在通过applicationContext发送通知的时候,事件会被两个容器发布,造成上述情况。

四、解决方案

知道了原因,解决方案就比较简单了,看了网上大多数的方案都是

Java代码  收藏代码
  1. @Override  
  2. public void onApplicationEvent(ContextRefreshedEvent event) {  
  3.     if(event.getApplicationContext().getParent() == null){  
  4.          //需要执行的逻辑代码,当spring容器初始化完成后就会执行该方法。  
  5.     }  
  6. }  

 但这种方案先定了事件的类型,自定义的事件是行不通的,所以解决方案的思路是用父容器去发送通知

Java代码  收藏代码
  1. /** 
  2.  * 通知事件 
  3.  * 
  4.  * @param applicationEvent 
  5.  */  
  6. public static void pushEvent(ApplicationEvent applicationEvent) {  
  7.     //获取父容器发送事件  
  8.     ContextLoader.getCurrentWebApplicationContext().publishEvent(applicationEvent);  
  9. }  

 测试结果:

Java代码  收藏代码
  1. myEvent occured msg : publish  

 至此,解决了这个case的问题,多大家有更好更多的方案,希望留言一起学习


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值