`
downpour
  • 浏览: 716096 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
00a07ae5-264f-3774-8903-8ad88ce08cb0
Struts2技术内幕
浏览量:117507
4d8508f2-c0dd-3df8-9483-04cc612afbbc
SpringMVC深度探险...
浏览量:230425
社区版块
存档分类
最新评论

一个简单的ServletContextLoader装载器

    博客分类:
  • Java
阅读更多
在很多项目中,会碰到一种需求,就是在应用服务器启动的时候,把一些东西从数据库里面读到内存中去。例如,对于一些权限信息,或者一些数据字典等等。实现这种需求本身不是很困难,写一个类,然后实现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。

好了,收工,洗手。
分享到:
评论
3 楼 LinApex 2013-08-05  
其实个人感觉没有必要,Spring 中有一个 资源加载完成之后,回调接口,如:BeanFactoryAware,在其中写接口,工厂,实现类即可,松耦合,高内聚。
2 楼 downpour 2006-09-26  
Readonly 写道
既然你都和spring绑定到一起用了,为啥还需要listener呢?
在某个setup bean的afterPropertiesSet() 方法里面做初始化的动作不就OK了吗?

如果没有spring,也可以在web.xml里面配置context-param,多设置几个setup bean的class name,然后统一由一个Listener读入不也OK吗?


一开始是考虑如果初始化过程无论有数据库读还是写操作,想用到Spring的事务管理。

不过你说得对,既然和Spring绑在一起了,就在afterPropertiesSet()方法里面做初始化动作好了。一开始没想到,脑子进水了。搞得那么麻烦,回去改掉。
1 楼 Readonly 2006-09-26  
既然你都和spring绑定到一起用了,为啥还需要listener呢?
在某个setup bean的afterPropertiesSet() 方法里面做初始化的动作不就OK了吗?

如果没有spring,也可以在web.xml里面配置context-param,多设置几个setup bean的class name,然后统一由一个Listener读入不也OK吗?

相关推荐

    链接器和装载器

    链接器的主要任务是将编译后的对象文件(通常由编译器生成)合并成一个单一的可执行文件或库。这些对象文件包含了程序的机器代码,但它们各自独立,没有包含完整的程序信息。链接器的工作就是解决函数和变量的引用,...

    Java深度历险(2)--深入类装载器

    在现代软件开发领域,特别是使用Java这样的高级编程语言时,“动态性”是一个非常重要的概念。它指的是程序能够在运行时根据需要加载、卸载或替换部分代码的能力。这对于提高系统的灵活性、可扩展性和安全性至关重要...

    java类装载器学习一、类加载器的基本概念

    类装载器学习一、类加载器的基本概念 类装载器学习一、类加载器的基本概念 类装载器学习一、类加载器的基本概念

    Java的类装载器和命名空间

    当一个类装载器接收到加载类的请求时,它首先会委托其父类装载器尝试加载,只有当父类装载器无法找到或加载该类时,才会尝试自己加载。这样可以防止恶意代码覆盖系统核心类,保证类的唯一性。 这个模型可以用层次...

    jvm类装载器原理

    特别地,JVM有一个内置的根装载器(bootstrap ClassLoader),它加载的是Java核心库中的类,被认为是安全且可信的。对于非预定义的类,就需要用户自定义的类装载器来完成加载。 自定义类装载器的应用广泛,例如在...

    破解的装载器方法.pdf [评价可免费]

    装载器一个程序,它能够把另一个程序载入内存并运行。每次你启动一个程序,标准的window装载器在幕后替你做这项工作。装载器有许多种,但是所有装载器基本上可以分为两大类型: l 标准的装载器 l 调试器装载器 1.1.1...

    装载问题的算法

    描述:此段代码展示了一个典型的装载问题解决方法,采用的是回溯法(backtracking)而非描述中的贪心算法。装载问题(也称为背包问题)是计算机科学与运筹学中一个经典的问题,主要研究如何在有限的资源下,通过选择...

    深入JVM内核—原理、诊断与优化视频教程-6. 类装载器

    1. **类装载器的层次结构**:Java的类装载器采用双亲委派模型,即当一个类装载器接到加载类的请求时,它首先会委托父类装载器去尝试加载,只有当父类装载器无法加载时,子类装载器才会尝试自己加载。这种模型保证了...

    最优装载问题 c++

    通过以上步骤,我们可以使用C++实现一个高效的最优装载问题求解器,以解决实际问题中的装载优化挑战。在编写代码时,需要注意数据结构的选择(如使用vector或数组)、内存管理以及效率优化等方面,以确保程序的正确...

    [浅析J2EE应用服务器的JAVA类装载器]python回朔异常的模块.docx

    当JVM请求加载一个类时,装载器首先将请求传递给其父装载器。只有当父装载器无法加载该类时,当前装载器才会尝试加载。这种结构形成了一个树形层次,根装载器(Bootstrap ClassLoader)位于顶部,它负责加载JVM运行...

    最优装载 有一批集装箱要装上一艘载重量为c的轮船。其中集装箱i的重量为Wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。

    为了解决这个问题,我们可以采用一种简单的贪心算法策略:按集装箱的重量降序排列,然后依次尝试装载每一个集装箱。这种方法的基本思想是先尽可能地装载较重的集装箱,直到不能再装载更多的集装箱为止。 #### 四、...

    嵌入式Linux装载器分析.pdf

    每个装载器都有其特定的功能集和适用场景,开发者需要根据目标系统的硬件配置、存储需求和性能要求来选择合适的装载器。移植装载器涉及到对目标硬件的理解,包括CPU指令集、内存管理、外设初始化等。同时,开发者还...

    装载问题.回溯法

    回溯法”指的是一个经典的计算机算法问题,它涉及到如何有效地在有限的资源条件下,如一艘船的载重限制,装载物品以最大化装载量或价值。在这个问题中,通常需要找到一种最优的装载组合,使得船只能够承载最大的重量...

    Android装载器的使用

    在Android应用开发中,装载器(Loader)是一个关键组件,它负责异步加载数据到UI,使得用户界面在数据加载过程中保持响应性。装载器设计的主要目标是解决数据的生命周期管理和UI更新问题,特别是在配置变更时,如...

    main_Celesteeverest_蔚蓝mod装载器_

    《蔚蓝》作为一个深受玩家喜爱的独立平台跳跃游戏,其模组社区也相当活跃,提供了许多创新和有趣的玩法。而“CelesteEverest”就是为了让玩家更便捷地享受这些模组而诞生的工具。 在下载的压缩包中,包含了若干关键...

    装载问题回溯算法

    然后,创建一个`LoadingProblem`类来管理整个装载问题的状态,包括船只的承载限制、货物列表和当前装载状态。`solve()`函数作为主要的回溯算法实现,通过递归调用来遍历所有可能的解决方案。 回溯算法的优点在于它...

    java之jvm学习笔记五(实践写自己的类装载器)

    在深入理解JVM的过程中,编写自己的类装载器(ClassLoader)是一个非常实用且有趣的实践。这个“java之jvm学习笔记五(实践写自己的类装载器)”很可能是对这一主题的详细探讨。 类装载器在Java中的主要职责是动态...

    C++最优装载问题

    在计算机科学和编程领域,最优装载问题是一个经典的运筹学问题,它涉及到如何高效地安排有限空间内的物品装载,以达到最大的效益。在这个问题中,我们通常考虑一系列具有不同重量和价值的物品,目标是选择一部分物品...

Global site tag (gtag.js) - Google Analytics