SSI框架下同一个Bean加载了2次问题解决
SSI框架下同一个Bean加载了2次
问题:需要通过http请求读取开放平台的数据。但是由于某一条数据量太大,用户使用的时候需要等待的时间过长。所以想通过缓存来解决,但是线上的缓存每隔一段时间会清理一次。于是用定时器每隔一段时间去执行校验拉取的操作,如果缓存有相应的数据就不执行任何操作,如果缓存中没有相应的数据,那么就重新读取接口得到数据缓存。
public void init() {
log.info("进入init方法");
new Timer().schedule(new TimerTask() {
@Override
public void run() {
log.info("定时器开始执行");
}
}, 0, 6 * 60 * 60 * 1000);
}
整个项目用的是SSI,在spring配置init-method,每次重启服务的时候执行定时器。这一切都执行的很顺利,并且在定时器中打了启动日志,以便观察它的启用情况。发现每次服务器重启的时候这个init方法都会执行2次。然后又在本地相同的代码跑了一遍发现在本地只执行了一次。于是上网查了一些资料。问题大概定位到是“ Spring(实例被构造两次)”,继续查找问题发现造成该现象主要有以下两个方面
- applicationContext.xml在加载的时候会被DispatcherServlet和ContextLoaderListener加载两次。
- Tomcat的server.xml配置文件的Host节点的属性 appBase='webapps'同时还配置了Context元素并且其docBase属性指向webapps下的该工程。这样子这个工程就会被加载2次。bean也就会被加载2次
关于第一个观点,查的资料作者用的是spring自带的quartz定时器。因为时间有限没有去实现。
(PS:web.xml配置下的ContextLoaderListener监听器。如果context-param不指定的话会去加载/WEB-INF/applicationContext.xml下的文件。
DispatcherServlet如果init-param不指定的话会自动加载[servlet-name]-servlet.xml。)
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>[servlet-name]</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:servletContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
这里如果ContextLoaderListener和DispatcherServlet加载的配置文件都一样的话。那么可能这个init方法会被执行两次。
但是我去看了下我得web.xml的配置,这两个类加载的xml文件都有明确说明的。所以造成第一个观点是不是这个原因造成的。以后有时间一定要去证实一下。说到底这都是spring和struts源码上做的文章。
结论:Tomcat的server.xml配置文件appBase属性至为空。