Spring自定義Listener(監聽器)的使用
文章轉自:https://blog.csdn.net/L253272670/article/details/77715899
在java web專案中我們通常會有這樣的需求:當專案啟動時執行一些初始化操作,例如從資料庫載入全域性配置檔案等,通常情況下我們會用javaee規範中的Listener去實現,例如
public class ConfigListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { //執行初始化操作 } @Override public void contextDestroyed(ServletContextEvent sce) { } }
這樣當servlet容器初始化完成後便會呼叫contextInitialized方法。但是通常我們在執行初始化的過程中會呼叫service和dao層提供的方法,而現在web專案通常會採用spring框架來管理和裝配bean,我們想當然會像下面這麼寫,假設執行初始化的過程中需要呼叫ConfigService的initConfig方法,而ConfigService由spring容器管理(標有@Service註解)
public class ConfigListener implements ServletContextListener { @Autowired private ConfigService configService; @Override public void contextInitialized(ServletContextEvent sce) { configService.initConfig(); } @Override public void contextDestroyed(ServletContextEvent sce) { } }
然而以上程式碼會在專案啟動時丟擲空指標異常!ConfigService例項並沒有成功注入。這是為什麼呢?要理解這個問題,首先要區分Listener的生命週期和spring管理的bean的生命週期。
(1)Listener的生命週期是由servlet容器(例如tomcat)管理的,專案啟動時上例中的ConfigListener是由servlet容器例項化並呼叫其contextInitialized方法,而servlet容器並不認得@Autowired註解,因此導致ConfigService例項注入失敗。
(2)而spring容器中的bean的生命週期是由spring容器管理的。
4.那麼該如何在spring容器外面獲取到spring容器bean例項的引用呢?這就需要用到spring為我們提供的WebApplicationContextUtils工具類,該工具類的作用是獲取到spring容器的引用,進而獲取到我們需要的bean例項。程式碼如下
public class ConfigListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ConfigService configService = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext()).getBean(ConfigService.class);
configService.initConfig();
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
注意:以上程式碼有一個前提,那就是servlet容器在例項化ConfigListener並呼叫其方法之前,要確保spring容器已經初始化完畢!而spring容器的初始化也是由Listener(ContextLoaderListener)完成,因此只需在web.xml中先配置初始化spring容器的Listener,然後在配置自己的Listener,配置如下
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>example.ConfigListener</listener-class>
</listener>