在很多项目中,会碰到一种需求,就是在应用服务器启动的时候,把一些东西从数据库里面读到内存中去。例如,对于一些权限信息,或者一些数据字典等等。实现这种需求本身不是很困难,写一个类,然后实现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。
好了,收工,洗手。
分享到:
相关推荐
链接器的主要任务是将编译后的对象文件(通常由编译器生成)合并成一个单一的可执行文件或库。这些对象文件包含了程序的机器代码,但它们各自独立,没有包含完整的程序信息。链接器的工作就是解决函数和变量的引用,...
在现代软件开发领域,特别是使用Java这样的高级编程语言时,“动态性”是一个非常重要的概念。它指的是程序能够在运行时根据需要加载、卸载或替换部分代码的能力。这对于提高系统的灵活性、可扩展性和安全性至关重要...
类装载器学习一、类加载器的基本概念 类装载器学习一、类加载器的基本概念 类装载器学习一、类加载器的基本概念
当一个类装载器接收到加载类的请求时,它首先会委托其父类装载器尝试加载,只有当父类装载器无法找到或加载该类时,才会尝试自己加载。这样可以防止恶意代码覆盖系统核心类,保证类的唯一性。 这个模型可以用层次...
特别地,JVM有一个内置的根装载器(bootstrap ClassLoader),它加载的是Java核心库中的类,被认为是安全且可信的。对于非预定义的类,就需要用户自定义的类装载器来完成加载。 自定义类装载器的应用广泛,例如在...
通过以上步骤,我们可以使用C++实现一个高效的最优装载问题求解器,以解决实际问题中的装载优化挑战。在编写代码时,需要注意数据结构的选择(如使用vector或数组)、内存管理以及效率优化等方面,以确保程序的正确...
装载器一个程序,它能够把另一个程序载入内存并运行。每次你启动一个程序,标准的window装载器在幕后替你做这项工作。装载器有许多种,但是所有装载器基本上可以分为两大类型: l 标准的装载器 l 调试器装载器 1.1.1...
描述:此段代码展示了一个典型的装载问题解决方法,采用的是回溯法(backtracking)而非描述中的贪心算法。装载问题(也称为背包问题)是计算机科学与运筹学中一个经典的问题,主要研究如何在有限的资源下,通过选择...
1. **类装载器的层次结构**:Java的类装载器采用双亲委派模型,即当一个类装载器接到加载类的请求时,它首先会委托父类装载器去尝试加载,只有当父类装载器无法加载时,子类装载器才会尝试自己加载。这种模型保证了...
当JVM请求加载一个类时,装载器首先将请求传递给其父装载器。只有当父装载器无法加载该类时,当前装载器才会尝试加载。这种结构形成了一个树形层次,根装载器(Bootstrap ClassLoader)位于顶部,它负责加载JVM运行...
每个装载器都有其特定的功能集和适用场景,开发者需要根据目标系统的硬件配置、存储需求和性能要求来选择合适的装载器。移植装载器涉及到对目标硬件的理解,包括CPU指令集、内存管理、外设初始化等。同时,开发者还...
为了解决这个问题,我们可以采用一种简单的贪心算法策略:按集装箱的重量降序排列,然后依次尝试装载每一个集装箱。这种方法的基本思想是先尽可能地装载较重的集装箱,直到不能再装载更多的集装箱为止。 #### 四、...
在Android应用开发中,装载器(Loader)是一个关键组件,它负责异步加载数据到UI,使得用户界面在数据加载过程中保持响应性。装载器设计的主要目标是解决数据的生命周期管理和UI更新问题,特别是在配置变更时,如...
回溯法”指的是一个经典的计算机算法问题,它涉及到如何有效地在有限的资源条件下,如一艘船的载重限制,装载物品以最大化装载量或价值。在这个问题中,通常需要找到一种最优的装载组合,使得船只能够承载最大的重量...
《蔚蓝》作为一个深受玩家喜爱的独立平台跳跃游戏,其模组社区也相当活跃,提供了许多创新和有趣的玩法。而“CelesteEverest”就是为了让玩家更便捷地享受这些模组而诞生的工具。 在下载的压缩包中,包含了若干关键...
在深入理解JVM的过程中,编写自己的类装载器(ClassLoader)是一个非常实用且有趣的实践。这个“java之jvm学习笔记五(实践写自己的类装载器)”很可能是对这一主题的详细探讨。 类装载器在Java中的主要职责是动态...
然后,创建一个`LoadingProblem`类来管理整个装载问题的状态,包括船只的承载限制、货物列表和当前装载状态。`solve()`函数作为主要的回溯算法实现,通过递归调用来遍历所有可能的解决方案。 回溯算法的优点在于它...
在计算机科学和编程领域,最优装载问题是一个经典的运筹学问题,它涉及到如何高效地安排有限空间内的物品装载,以达到最大的效益。在这个问题中,我们通常考虑一系列具有不同重量和价值的物品,目标是选择一部分物品...