在某些情況下,有可能你會有這種需求:在Spring/SpringMVC項目中,當Spring/SpringMVC啟動完成后,你需要執行一個方法來完成某些事件(比如創建網站地圖,比如從訂閱Redis服務器等),這個時候,可以使用Tomcat/Servlet容器提供的事件回調機制來完成,但是這樣有個問題是:無法使用Spring提供的Annotation,解決方法是:
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.storezhang.web; import com.storezhang.util.TimeUtils; import com.storezhang.video.util.SiteMapUtils; import java.util.Timer; import java.util.TimerTask; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Service; /** * 啟動監聽器 * * @author Storezhang */ @Service public class StartupListener implements ApplicationListener<ContextRefreshedEvent> { @Autowired private SiteMapUtils sites; @Override public void onApplicationEvent(ContextRefreshedEvent evt) { if (evt.getApplicationContext().getParent() == null) { createSitemap(); } } private void createSitemap() { Timer timer = new Timer("createSitemap", true); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("--->Create sitemap..."); sites.createSiteMap(); System.out.println("--->Success create sitemap..."); } }, 1 * TimeUtils.MIN); } }
后續研究:
applicationontext和使用MVC之后的webApplicationontext會兩次調用上面的方法,如何區分這個兩種容器呢?
但是這個時候,會存在一個問題,在web 項目中(spring mvc),系統會存在兩個容器,一個是root application context ,另一個就是我們自己的 projectName-servlet context(作為root application context的子容器)。
這種情況下,就會造成onApplicationEvent方法被執行兩次。為了避免上面提到的問題,我們可以只在root application context初始化完成后調用邏輯代碼,其他的容器的初始化完成,則不做任何處理,修改后代碼
如下:
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if(event.getApplicationContext().getParent() == null){//root application context 沒有parent,他就是老大.
//需要執行的邏輯代碼,當spring容器初始化完成后就會執行該方法。
}
}