SpringMVC中web.xml分析一

最近项目在使用springMVC+hibernate,以前从来没仔细研究过项目结构及配置文件,现在项目不是很忙,对项目结构及配置简单了解下,并做一些记录,以便加深印象。首先是项目配置文件web.xml。

以下是公司项目中context-param 和 listener的定义。

<!--定义了web应用的名称-->
<display-name>ld_cms</display-name>
<!--该元素声明应用范围内的初始化参数-->
<context-param>
        <!--用于指定上下文参数的名称-->
        <param-name>contextConfigLocation</param-name>
        <!--用于指定上下文参数的值-->
        <param-value>
            /WEB-INF/config/core/application-context.xml
        </param-value>
</context-param>
<!--servlet API的版本2.3增加了对事件监听程序的支持,事件监听程序在建立、修改和删除会话或servlet环境时得到通知。Listener元素指出事件监听程序类-->
<listener>
        <!--用于指定监听器的类-->
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

springmvc关于以上内容的加载过程是context-param >> listener  >> fileter  >> servlet:

  1. 在启动Web项目时,容器(比如Tomcat)会读web.xml配置文件中的两个节点<listener>和<contex-param>。
  2. 接着容器会创建一个ServletContext(上下文),应用范围内即整个WEB项目都能使用这个上下文。
  3. ContextLoaderListener实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。


下面简单的看一下ContextLoaderListener的源代码


/**
* Initialize the root web application context.
*/
public void contextInitialized(ServletContextEvent event) {
	this.contextLoader = createContextLoader();
	if (this.contextLoader == null) {
		this.contextLoader = this;
	}
	this.contextLoader.initWebApplicationContext(event.getServletContext());
}
由以上代码可知真在的实现是有代理类contextLoader做的。于是我们来到initWebApplicationContext(ServletContext servletContext) 方法。
/**
 * Initialize Spring's web application context for the given servlet context,
 * using the application context provided at construction time, or creating a new one
 * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
 * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
 * @param servletContext current servlet context
 * @return the new WebApplicationContext
 * @see #ContextLoader(WebApplicationContext)
 * @see #CONTEXT_CLASS_PARAM
 * @see #CONFIG_LOCATION_PARAM
 */
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
        throw new IllegalStateException(
                "Cannot initialize context because there is already a root application context present - " +
                "check whether you have multiple ContextLoader* definitions in your web.xml!");
    }

    Log logger = LogFactory.getLog(ContextLoader.class);
    servletContext.log("Initializing Spring root WebApplicationContext");
    if (logger.isInfoEnabled()) {
        logger.info("Root WebApplicationContext: initialization started");
    }
    long startTime = System.currentTimeMillis();

    try {
        // Store context in local instance variable, to guarantee that
        // it is available on ServletContext shutdown.
        if (this.context == null) {
            this.context = createWebApplicationContext(servletContext);
        }
        if (this.context instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
            if (!cwac.isActive()) {
                // The context has not yet been refreshed -> provide services such as
                // setting the parent context, setting the application context id, etc
                if (cwac.getParent() == null) {
                    // The context instance was injected without an explicit parent ->
                    // determine parent for root web application context, if any.
                    ApplicationContext parent = loadParentContext(servletContext);
                    cwac.setParent(parent);
                }
                configureAndRefreshWebApplicationContext(cwac, servletContext);
            }
        }
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
        if (ccl == ContextLoader.class.getClassLoader()) {
            currentContext = this.context;
        }
        else if (ccl != null) {
            currentContextPerThread.put(ccl, this.context);
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
                    WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
        }
        if (logger.isInfoEnabled()) {
            long elapsedTime = System.currentTimeMillis() - startTime;
            logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
        }

        return this.context;
    }
    catch (RuntimeException ex) {
        logger.error("Context initialization failed", ex);
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
        throw ex;
    }
    catch (Error err) {
        logger.error("Context initialization failed", err);
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
        throw err;
    }
}

首次进入由createWebApplicationContext(servletContext)创建WebApplicationContext对象。

/**
 * Instantiate the root WebApplicationContext for this loader, either the
 * default context class or a custom context class if specified.
 * <p>This implementation expects custom contexts to implement the
 * {@link ConfigurableWebApplicationContext} interface.
 * Can be overridden in subclasses.
 * <p>In addition, {@link #customizeContext} gets called prior to refreshing the
 * context, allowing subclasses to perform custom modifications to the context.
 * @param sc current servlet context
 * @return the root WebApplicationContext
 * @see ConfigurableWebApplicationContext
 */
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
    Class<?> contextClass = determineContextClass(sc);
    if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
        throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
                "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
    }
    return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}

进入determineContextClass(ServletContext servletContext)方法。

/**
 * Return the WebApplicationContext implementation class to use, either the
 * default XmlWebApplicationContext or a custom context class if specified.
 * @param servletContext current servlet context
 * @return the WebApplicationContext implementation class to use
 * @see #CONTEXT_CLASS_PARAM
 * @see org.springframework.web.context.support.XmlWebApplicationContext
 */
protected Class<?> determineContextClass(ServletContext servletContext) {
    String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
    if (contextClassName != null) {
        try {
            return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
        }
        catch (ClassNotFoundException ex) {
            throw new ApplicationContextException(
                    "Failed to load custom context class [" + contextClassName + "]", ex);
        }
    }
    else {
        contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
        try {
            return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
        }
        catch (ClassNotFoundException ex) {
            throw new ApplicationContextException(
                    "Failed to load default context class [" + contextClassName + "]", ex);
        }
    }
}
首先如果在web.xml中的<context-param> </context-param>中定义了参数contextClass,那么直接就决定了用此Context类。否则获取对象defaultStrategies中的WebApplicationContext属性。defaultStrategies的定义如下:

static {
    // Load default strategy implementations from properties file.
    // This is currently strictly internal and not meant to be customized
    // by application developers.
    try {
        ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
        defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
    }
    catch (IOException ex) {
        throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
    }
}
获取ContextLoader.properties内容。内容如下:

# Default WebApplicationContext implementation class for ContextLoader.
# Used as fallback when no explicit context implementation has been specified as context-param.
# Not meant to be customized by application developers.
 
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

综上所知,最终创建的对象为XmlWebApplicationContext对象。XmlWebApplicationContext继承了AbstractRefreshableWebApplicationContext类中定义的 方法protected String[] getConfigLocations() ,这个方法默认可以加载contextConfigLocation中定义的xml 文件,如果你重写了这个方法还可以在任意地方加载你想要的xml文件。如果没有定义context-param,则取/WEB-INF/applicationContext.xml,否则就取定义的contextConfigLocation。


以上内容即为context-param和ContextLoaderListener的配置分析。

吐槽一下编辑器,真是好麻烦。接触java时间并不是很长,有理解的不对和错误的地方希望大家能指出,谢谢。


文章参照:

http://blog.csdn.net/jubincn/article/details/9115205

http://blog.csdn.net/ysughw/article/details/8992322

http://yangzb.iteye.com/blog/834633

http://www.blogjava.net/charles/archive/2008/12/26/248497.html





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值