一、case复现
事件定义
- public class MyEvent extends ApplicationEvent {
- public MyEvent(Object object) {
- super(object);
- }
- }
监听定义
- @Component
- public class MyListener implements ApplicationListener<MyEvent> {
- @Override
- public void onApplicationEvent(MyEvent event) {
- System.out.println("myEvent occured msg : " + event.getSource());
- }
- }
事件通知
- @ResponseBody
- @RequestMapping(value = "/publish")
- public String publish(String key) {
- BeanFactory.pushEvent(new MyEvent("publish"));
- return "success";
- }
- @Component
- public class BeanFactory implements ApplicationContextAware {
- private static ApplicationContext applicationContext;
- public static <T> T getBean(String beanName, Class<T> clazz) {
- return (T) applicationContext.getBean(beanName);
- }
- /**
- * 通知事件
- *
- * @param applicationEvent
- */
- public static void pushEvent(ApplicationEvent applicationEvent) {
- //获取父容器发送事件
- //ContextLoader.getCurrentWebApplicationContext().publishEvent(applicationEvent);
- applicationContext.publishEvent(applicationEvent);
- }
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- this.applicationContext = applicationContext;
- }
- public static ApplicationContext getApplicationContext() {
- return applicationContext;
- }
- }
测试结果:
- myEvent occured msg : publish
- myEvent occured msg : publish
三、原因
在web项目中如果同时集成了spring和springMVC的话,上下文中会存在两个容器,即spring的applicationContext.xml的父容器和springMVC的applicationContext-mvc.xml的子容器。
在通过applicationContext发送通知的时候,事件会被两个容器发布,造成上述情况。
四、解决方案
知道了原因,解决方案就比较简单了,看了网上大多数的方案都是
- @Override
- public void onApplicationEvent(ContextRefreshedEvent event) {
- if(event.getApplicationContext().getParent() == null){
- //需要执行的逻辑代码,当spring容器初始化完成后就会执行该方法。
- }
- }
但这种方案先定了事件的类型,自定义的事件是行不通的,所以解决方案的思路是用父容器去发送通知
- /**
- * 通知事件
- *
- * @param applicationEvent
- */
- public static void pushEvent(ApplicationEvent applicationEvent) {
- //获取父容器发送事件
- ContextLoader.getCurrentWebApplicationContext().publishEvent(applicationEvent);
- }
测试结果:
- myEvent occured msg : publish
至此,解决了这个case的问题,多大家有更好更多的方案,希望留言一起学习
本文介绍了Spring事件机制中onApplicationEvent方法被执行两次的案例复现,详细分析了原因——在Web项目中由于存在父子容器导致事件重复发布。并提供了针对性的解决方案,通过使用父容器来发送事件,确保只触发一次。测试结果显示问题已成功解决。

1635

被折叠的 条评论
为什么被折叠?



