web.xml下几个特殊的配置

2018/04/13 Java

记录下web项目下web.xml中遇到的特殊的配置,并且记录了自己对其的理解。

ServletContext监听器

org.springframework.web.context.ContextLoaderListener

ContextLoaderListener的作用就是启动Web容器时,自动装配ApplicationContext.xml的配置信息。因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。

org.springframework.web.context.ContextLoaderListener类实现了javax.servlet.ServletContextListener接口。

ServletContextListener接口能够监听ServletContext对象的生命周期,因为每个web应用仅有一个ServletContext对象,故实际上该接口监听的是整个web应用。

实现该接口的类在web.xml中作为监听器配置后,当web应用启动后,会触发ServletContextEvent事件,调用ContextLoaderListener的contextInitialized(ServletContextEvent sce)方法。

ContextLoaderListener通过一个ContextLoader对象来初始化Spring容器。在contextInitialized方法中调用contextLoader.initWebApplicationContext(event.getServletContext())。

ContextLoader类的initWebApplicationContext方法即可返回一个WebApplicationContext对象context。

并通过 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context)将WebApplicationContext对象放置在ServletContext对象中

initWebApplicationContext方法通过调用以下方法实例化并设置WebApplicationContext对象。

protected WebApplicationContext createWebApplicationContext(ServletContext servletContext, ApplicationContext parent) throws BeansException { Class contextClass = determineContextClass(servletContext);//通过servletContext确定WebApplicationContext的具体类型

    if(!(org.springframework.web.context.ConfigurableWebApplicationContext.class).isAssignableFrom(contextClass))
    {
        throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + (org.springframework.web.context.ConfigurableWebApplicationContext.class).getName() + "]");
    } 
	else
    {
        ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
        wac.setParent(parent);
        wac.setServletContext(servletContext);
        wac.setConfigLocation(servletContext.getInitParameter("contextConfigLocation"));//设置配置文件的路径名
        customizeContext(servletContext, wac);
        wac.refresh();
        return wac;
    }
}

因此可以通过WebApplicationContextUtils.getWebApplicationContext(ServletContext sc)获取WebApplicationContext。

内部实现是通过servletContext对象查找该对象,属性名为WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。

Spring内存溢出监听器

org.springframework.web.util.IntrospectorCleanupListener

这是Introspector 缓存清除监听器

Spring 提供了一个名为 org.springframework.web.util.IntrospectorCleanupListener 的监听器。

它主要负责处理由 JavaBean Introspector 功能而引起的缓存泄露。

IntrospectorCleanupListener 监听器在 Web 应用关闭的时会负责清除 JavaBean Introspector 的缓存,

在 web.xml 中注册这个监听器可以保证在 Web 应用关闭的时候释放与其相关的 ClassLoader 的缓存和类引用。

如果您使用了 JavaBean Introspector 分析应用中的类,Introspector 缓存会保留这些类的引用,结果在应用关闭的时候,这些类以及Web 应用相关的 ClassLoader 不能被垃圾回收。

不幸的是,清除 Introspector 的唯一方式是刷新整个缓存,这是因为没法准确判断哪些是属于本 Web 应用的引用对象,哪些是属于其它 Web 应用的引用对象。

所以删除被缓存的 Introspection 会导致将整个 JVM 所有应用的 Introspection 都删掉。

需要注意的是,Spring 托管的 Bean 不需要使用这个监听器,因为 Spring 的 Introspection 所使用的缓存在分析完一个类之后会马上从 javaBean Introspector 缓存中清除掉,

并将缓存保存在应用程序特定的 ClassLoader 中,所以它们一般不会导致内存资源泄露。

但是一些类库和框架往往会产生这个问题。

例如 Struts 和 Quartz 的 Introspector 的内存泄漏会导致整个的 Web 应用的 ClassLoader 不能进行垃圾回收。

在 Web 应用关闭之后,您还会看到此应用的所有静态类引用,这个错误当然不是由这个类自身引起的。

解决这个问题的方法很简单,您仅需在 web.xml 中配置 IntrospectorCleanupListener 监听器就可以了

Show Disqus Comments

Search

    Table of Contents