浏览 3798 次
|
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
|---|---|
| 作者 | 正文 |
|
时间:2006-09-26 关键字: Spring ServletContext ServletContextListener
在很多项目中,会碰到一种需求,就是在应用服务器启动的时候,把一些东西从数据库里面读到内存中去。例如,对于一些权限信息,或者一些数据字典等等。实现这种需求本身不是很困难,写一个类,然后实现ServletContextListener这个接口,再到web.xml里面去配置一下就可以了。(我想已经有很多应用服务器支持ServletContextListener这个接口了吧,像Websphere5.0这种垃圾除外)
现在的问题是,由于需求是不断变化的,说不定哪天增加了一个又要在系统启动时往内存里面写点啥。此时,要么在原来的类的后面,加一段代码,要么就再写一个类,再配一个Listener。一般我会采用后面一种做法,因为这样至少可以做到对这些Listener保持可配置性,当业务发生变化时,简单改变配置文件就可以完成需求。不过这带来了一个问题,就是有可能web.xml就比较凌乱,而且还要搞清楚和其他一些系统启动运行的Listener的关系。 所以最近根据这个情况设计了一个简单的ServletContextLoader的装载器。在web.xml里面只需要配置一个Listener,而这个listener的作用就是依次按顺序调用其他的Listener。此时,其他的Listener都可以通过Spring的注入进入这个总的Listener服从调度。
/**
* @author zhou.lu
*/
public class ServletContextLoaderListener implements ServletContextListener {
private static final Log logger = LogFactory.getLog(ServletContextLoaderListener.class);
private ServletContextLoader servletContextLoader;
public void contextInitialized(ServletContextEvent event) {
this.servletContextLoader = createServletContextLoader(event);
this.servletContextLoader.initServletContext(event.getServletContext());
}
private ServletContextLoader createServletContextLoader(ServletContextEvent event) {
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
return (ServletContextLoader) applicationContext.getBean("servletContextLoader");
}
public void contextDestroyed(ServletContextEvent event) {
this.servletContextLoader.closeServletContext(event.getServletContext());
}
}
这个就是一个总的Listener,这里模仿了Spring的源码,将具体的调度指派给ServletContextLoader这个接口来完成,而具体的实现则通过Spring拿到。接下来看一下它的具体实现:
/**
* @author zhou.lu
*/
public class ServletContextLoaderImpl implements ServletContextLoader, InitializingBean {
private static final Log logger = LogFactory.getLog(ServletContextLoaderImpl.class);
private List servletContextLoaders;
public void setServletContextLoaders(List servletContextLoaders) {
this.servletContextLoaders = servletContextLoaders;
}
public void afterPropertiesSet() throws Exception {
for (int i = 0; i < servletContextLoaders.size(); i++) {
// check every servletContextLoader and set to loaders
Object loader = servletContextLoaders.get(i);
if (!(loader instanceof ServletContextLoader)) {
throw new IllegalArgumentException("Unsupported ServletContextLoader:" + loader.getClass());
}
}
}
public void initServletContext(ServletContext servletContext) {
for (int i = 0; i < servletContextLoaders.size(); i++) {
ServletContextLoader loader = (ServletContextLoader) servletContextLoaders.get(i);
loader.initServletContext(servletContext);
}
}
public void closeServletContext(ServletContext servletContext) {
for (int i = 0; i < servletContextLoaders.size(); i++) {
ServletContextLoader loader = (ServletContextLoader) servletContextLoaders.get(i);
loader.closeServletContext(servletContext);
}
}
}
其实这个具体的实现就是做了所有的调度。而所有实现ServletContextLoader这个接口,并且被注入到这个类中去的ServletContextLoader会被依次执行其中的方法。因而,所以如果以后要做系统启动时的数据加载,只要简单实现ServletContextLoader这个接口,并且配置到Spring的配置文件中即可。例如:
public class MasterDataLoader implements ServletContextLoader {
private SystemService systemService;
public void initServletContext(ServletContext servletContext) {
// Master Data Loader
Map masterData = systemService.getMasterData();
// TODO Add to servletContext
}
public void closeServletContext(ServletContext servletContext) {
// TODO Clear servletContext
}
public void setSystemService(SystemService systemService) {
this.systemService = systemService;
}
}
然后是Spring的配置文件片断:
<bean id="systemService" parent="baseTxProxy">
<property name="target">
<bean class="com.adt.surecenter.service.impl.SystemServiceImpl"
autowire="byName"/>
</property>
</bean>
<bean id="commandMappingLoader" class="com.adt.surecenter.loader.CommandMappingLoader" autowire="byName" />
<bean id="masterDataLoader" class="com.adt.surecenter.loader.MasterDataLoader" autowire="byName" />
<bean id="servletContextLoader" class="com.adt.core.loader.ServletContextLoaderImpl" autowire="byName" >
<property name="servletContextLoaders">
<list>
<ref bean="masterDataLoader"/>
</list>
</property>
</bean>
最后别忘记在web.xml中配置最初写的那个Listener,并且放置在Spring的Listener之后,就ok了。 <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>com.adt.core.loader.ServletContextLoaderListener</listener-class> </listener> 此时,你在web.xml中的配置简化了,你所需要实现的具体的每个servletContextLoader看上去就像一个POJO,实现某个接口,收到Spring的管理,遵循Spring的IoC。 好了,收工,洗手。 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
时间:2006-09-26
既然你都和spring绑定到一起用了,为啥还需要listener呢?
在某个setup bean的afterPropertiesSet() 方法里面做初始化的动作不就OK了吗? 如果没有spring,也可以在web.xml里面配置context-param,多设置几个setup bean的class name,然后统一由一个Listener读入不也OK吗? |
|
| 返回顶楼 | |
|
时间:2006-09-26
Readonly 写道 既然你都和spring绑定到一起用了,为啥还需要listener呢?
在某个setup bean的afterPropertiesSet() 方法里面做初始化的动作不就OK了吗? 如果没有spring,也可以在web.xml里面配置context-param,多设置几个setup bean的class name,然后统一由一个Listener读入不也OK吗? 一开始是考虑如果初始化过程无论有数据库读还是写操作,想用到Spring的事务管理。 不过你说得对,既然和Spring绑在一起了,就在afterPropertiesSet()方法里面做初始化动作好了。一开始没想到,脑子进水了。搞得那么麻烦,回去改掉。 |
|
| 返回顶楼 | |





