在某些情况下,有可能你会有这种需求:在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容器初始化完成后就会执行该方法。
}
}