在應用啟動時,通常想在此時預加載一些資源,全局使用。
Spring會在操作應用上下文時,使用ApplicationEventPublisher觸發相關ApplicationContextEvent,我們可以監聽這些事件來做一些事情。
Spring中ApplicationContextEvent有以下幾種:
其中ContextRefreshedEvent的執行時機為:
1 Event raised when an {@code ApplicationContext} gets initialized or refreshed.
我們通常會在Spring加載或刷新應用上下文時,也重新刷新下我們預加載的資源,我們就可以通過監聽ContextRefreshedEvent來做這樣的事情。
代碼如下:
1 @Component 2 public class SpringHandlersProvider implements ApplicationListener<ContextRefreshedEvent> { 3 Lists<XXX> handlerList = Lists.newHashList(); 4 @Override 5 public void onApplicationEvent(ContextRefreshedEvent event) { 6 //do something 7 handlerList.add(xxx); 8 } 9 }
但對於tomcat工程來說,我們一般會加載兩個上下文容器一個父容器,一個mvc子容器
- 父容器{@code ContextRefreshedEvent[source=Root WebApplicationContext: startup date [Thu Sep 29 14:52:08 CST 2016]; root of context hierarchy]}
- mvc容器{@code ContextRefreshedEvent[source=WebApplicationContext for namespace 'springmvc-servlet': startup date [Thu Sep 29 14:52:34 CST 2016]; parent: Root WebApplicationContext]}
這樣就會觸發兩次ContextRefreshedEvent事件,導致監聽此事件所作的邏輯執行兩次。
避免方法:
1:只在加載父容器時,執行一次
1 @Component 2 public class SpringHandlersProvider implements ApplicationListener<ContextRefreshedEvent> { 3 Lists<XXX> handlerList = Lists.newHashList(); 4 @Override 5 public void onApplicationEvent(ContextRefreshedEvent event) { 6 if (Predicates.isNull().apply(event.getApplicationContext().getParent())) { 7 //do something 8 handlerList.add(xxx); 9 } 10 } 11 }
2:每次執行onApplicationEvent()方法時就將存放資源的容器清空下
1 @Component 2 public class SpringHandlersProvider implements ApplicationListener<ContextRefreshedEvent> { 3 Lists<XXX> handlerList = Lists.newHashList(); 4 @Override 5 public void onApplicationEvent(ContextRefreshedEvent event) { 6 handlerList.clear(); 7 8 //do something 9 handlerList.add(xxx); 10 } 11 }