ContextRefreshedEvent 事件会在Spring容器初始化完成会触发该事件。我们在实际工作也可以能会监听该事件去做一些事情,但是有时候使用不当也会带来一些问题。
防止重复触发
主要因为对于web应用会出现父子容器,这样就会触发两次,那么如何避免呢?下面给出两种简单的解决方案。
父子容简单说明:当一个项目中引入Spring和SpringMVC这两个框架,其实就是2个容器,Spring是父容器,SpringMVC是其子容器。
方案一:增加一个是否初始化的标识,进行初始化前判断标识。
@Component
public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {
// 增加一个标识
private volatile AtomicBoolean isInit=new AtomicBoolean(false);
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// CAS修改是否初始化标识,防止重复触发
if(!isInit.compareAndSet(false,true)) {
return;
}
init();
}
private void init() {
//开始初始化
}
}
方案二:通过判断ApplicationContext父类是否为null
@Component
public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// 判断父类是否存在,防止重复初始化
if (event.getApplicationContext().getParent() != null) {
return;
}
init();
}
private void init() {
//开始初始化
}
}
监听事件顺序问题
如果在项目中想要自己控制监听事件的执行顺序,可以通过实现SmartApplicationListener接口实现。
public class ContextRefreshedEventListener implements SmartApplicationListener {
/**
* 增加一个标识
*/
private volatile AtomicBoolean isInit = new AtomicBoolean(false);
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return eventType == ContextRefreshedEvent.class;
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return true;
}
@Override
public int getOrder() {
//值越小,就先触发
return 0;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
// 防止重复触发
if (!isInit.compareAndSet(false, true)) {
return;
}
init();
}
private void init() {
//开始初始化
}
}