spring event mechanism - onApplicationEvent is executed twice

1. Case recurrence

event definition

 

public class MyEvent extends ApplicationEvent {

    public MyEvent(Object object) {
        super(object);
    }
}

 

 

monitor definition

 

@Component
public class MyListener implements ApplicationListener<MyEvent> {

    @Override
    public void onApplicationEvent(MyEvent event) {
        System.out.println("myEvent occured msg : " + event.getSource());
    }
}

 

 

event notification

 

@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);
    }

    /**
     * Notify events
     *
     * @param applicationEvent
     */
    public static void pushEvent(ApplicationEvent applicationEvent) {
        //Get the event sent by the parent container
        //ContextLoader.getCurrentWebApplicationContext().publishEvent(applicationEvent);
        applicationContext.publishEvent(applicationEvent);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
}

 Test Results:

 

myEvent occured msg : publish
myEvent occured msg : publish

 

 

3. Reason

If both spring and springMVC are integrated in a web project, there will be two containers in the context, namely the parent container of spring's applicationContext.xml and the child container of springMVC's applicationContext-mvc.xml.

When a notification is sent through the applicationContext, the event will be published by both containers, causing the above.

4. Solutions

Knowing the reason, the solution is relatively simple. Most of the solutions on the Internet are

   @Override
   public void onApplicationEvent(ContextRefreshedEvent event) {
       if(event.getApplicationContext().getParent() == null){
            //The logic code that needs to be executed, this method will be executed when the spring container is initialized.
       }
   }

 However, this scheme predetermines the type of event, and custom events are not feasible, so the idea of ​​​​the solution is to use the parent container to send notifications

    /**
     * Notify events
     *
     * @param applicationEvent
     */
    public static void pushEvent(ApplicationEvent applicationEvent) {
        //Get the event sent by the parent container
        ContextLoader.getCurrentWebApplicationContext().publishEvent(applicationEvent);
    }

 Test Results:

myEvent occured msg : publish

 So far, the problem of this case has been solved, and everyone has better and more solutions. I hope to leave a message and learn together.

 

 

 

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326180683&siteId=291194637