onApplicationEvent调用了2次,3次,多次

onApplicationEvent调用了2次,3次,多次 解决方案

首先,被执行这么多次,肯定是自己配置的问题,我以spring boot为例来说

我也遇到了执行三次,排查后发现一个是spring boot的,另外两个是自己配的,所以才导致三次,理论上可以导致n次的
三个事件源分别为:

  1. spring boot 自带的注解形式上下文(解析所有通过开放端口发来的请求)
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@184497d1, started on Sat Oct 12 10:33:03 CST 2019
  1. 开发者自己创建的(仅负责解析 /ui/** 请求)
org.springframework.context.event.ContextRefreshedEvent[source=WebApplicationContext for namespace 'ui-servlet', started on Sat Oct 12 10:34:53 CST 2019, parent: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@184497d1]
  1. 开发者自己创建的(仅负责解析 /api/** 请求)
org.springframework.context.event.ContextRefreshedEvent[source=WebApplicationContext for namespace 'api-servlet', started on Sat Oct 12 10:35:06 CST 2019, parent: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@184497d1]

可以看到第一个是spring boot自身的,另外两个是 WebApplicationContext 的不同空间,而他们有同样的父容器(即第一个)


后面两个怎么来的?

@Configuration
public class ServletConfig {

    @Bean
    public ServletRegistrationBean dispatcherUI() {
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
        applicationContext.scan("com.xxx.*.controller.ui");
        DispatcherServlet dispatcherServlet = new DispatcherServlet(applicationContext);
        ServletRegistrationBean servletRegistration = new ServletRegistrationBean(dispatcherServlet,"/ui/*");
        servletRegistration.setName("ui"); // 起名
        return servletRegistration;
    }


    @Bean
    public ServletRegistrationBean dispatcherApi() {
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
        applicationContext.scan("com.xxx.*.controller.api");
        DispatcherServlet dispatcherServlet = new DispatcherServlet(applicationContext);
        ServletRegistrationBean servletRegistration = new ServletRegistrationBean(dispatcherServlet,"/api/*");
        servletRegistration.setName("api"); // 起名
        return servletRegistration;
    }
}

同时验证了 spring为它命名是 xxx-servlet,xxx是自己起的。


只想让它执行一次?

可见onApplicationEvent被调用多次并不是spring的bug,而是spring为开发者留的口子,即允许开发者自由自在的关心哪个,执行哪个即可,如果你不说,我就每次都通知你。

一般来说如果作为启动配置,不是特定容器的配置的话,只关心spring boot本身那个就好了,判断一下parent 是否为空即可。若为空则证明是root applicationContext。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章