Spring ApplicationListener使用方法及問題(onApplicationEvent被呼叫兩次)
阿新 • • 發佈:2019-04-03
使用場景
在一些業務場景中,當容器初始化完成之後,需要處理一些操作,比如一些資料的載入、初始化快取、特定任務的註冊等等。這個時候我們就可以使用Spring提供的ApplicationListener來進行操作。
用法
本文以在Spring boot下的使用為例來進行說明。首先,需要實現ApplicationListener介面並實現onApplicationEvent方法。把需要處理的操作放在onApplicationEvent中進行處理:
package com.secbro.learn.context; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; public class ApplicationStartListener implements ApplicationListener<ContextRefreshedEvent>{ @Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { System.out.println("我的父容器為:" + contextRefreshedEvent.getApplicationContext().getParent()); System.out.println("初始化時我被呼叫了。"); } }
然後,例項化ApplicationStartListener這個類,在Spring boot中通過一個配置類來進行例項化:
package com.secbro.learn.conf; import com.secbro.learn.context.ApplicationStartListener; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ListenerConfig { @Bean public ApplicationStartListener applicationStartListener(){ return new ApplicationStartListener(); } }
隨後,啟動Spring boot服務,打印出一下內容:
我的父容器為:null
初始化時我被呼叫了。
從列印的結果可以看出,ApplicationStartListener的onApplicationEvent方法在容器啟動時已經被成功呼叫了。而此時初始化的容器為root容器。
二次呼叫問題
此處使用Spring boot來進行操作,沒有出現二次呼叫的問題。在使用傳統的application.xml和project-servlet.xml配置中會出現二次呼叫的問題。主要原因是初始化root容器之後,會初始化project-servlet.xml對應的子容器。我們需要的是隻執行一遍即可。那麼上面列印父容器的程式碼用來進行判斷排除子容器即可。在業務處理之前新增如下判斷:
if(contextRefreshedEvent.getApplicationContext().getParent() != null){
return;
}if(contextRefreshedEvent.getApplicationContext().getParent() != null){
return;
}
這樣其他容器的初始化就會直接返回,而父容器(Parent為null的容器)啟動時將會執行相應的業務操作。
關聯知識
在spring中InitializingBean介面也提供了類似的功能,只不過它進行操作的時機是在所有bean都被例項化之後才進行呼叫。根據不同的業務場景和需求,可選擇不同