onApplicationEvent调用了2次,3次,多次 解决方案
首先,被执行这么多次,肯定是自己配置的问题,我以spring boot为例来说
我也遇到了执行三次,排查后发现一个是spring boot的,另外两个是自己配的,所以才导致三次,理论上可以导致n次的
三个事件源分别为:
- spring boot 自带的注解形式上下文(解析所有通过开放端口发来的请求)
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@184497d1, started on Sat Oct 12 10:33:03 CST 2019
- 开发者自己创建的(仅负责解析 /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]
- 开发者自己创建的(仅负责解析 /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。