JavaWeb 之web.xml配置中contextConfigLocation属性详解


contextConfigLocation一般配置在context-param标签中,下面首先了解context-param标签作用和Web初始化的简单过程。

context-param标签作用

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:spring-basic.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

作用:该元素用来声明应用范围(整个WEB项目)内的上下文初始化参数。

  • param-name:设定上下文的参数名称,必须是唯一名称。
  • param-value:设定的参数名称的值。

Web项目初始化过程

  • 启动一个WEB项目的时候,容器(比如:Tomcat)会读web.xml配置文件中的两个节点和。
  • 接着容器会创建一个ServletContext(上下文),整个WEB项目所有部分都将共享这个上下文。
  • 接着容器会将<context-param></context-param>转化为键值对,并交给ServletContext。
  • 容器创建<listener></listener>中的类实例,即创建监听(备注:listener定义的类可以是自定义的类但必须需要继承ServletContextListener)。
  • 在监听的类中会有一个contextInitialized(ServletContextEvent event)初始化方法,在这个方法中可以通过event.getServletContext().getInitParameter("contextConfigLocation") 来得到context-param设定的值。
  • 得到这个context-param的值之后,你就可以做一些操作了。注意,这个时候你的WEB项目还没有完全启动完成,这个动作会比所有的Servlet都要早。换句话说,这个时候,你对<context-param>中的键值做的操作,将在你的WEB项目完全启动之前被执行。
  • 举例,你可能想在项目启动之前就打开数据库,那么这里就可以在<context-param>中设置数据库的连接方式,在监听类中初始化数据库的连接。这个监听是自己写的一个类,除了初始化方法,它还有销毁方法。用于关闭应用前释放资源,比如说数据库连接的关闭。

由上面的初始化过程可知容器对于web.xml的加载过程是context-param >> listener >> fileter >> servlet

获取context-param定义的属性值

页面中:
${initParam.contextConfigLocation}
Servlet中:
String paramValue = getServletContext().getInitParameter(“contextConfigLocation”);

容器加载过程

  • Root WebApplicationContext:这是对J2EE三层架构中的service层、dao层进行配置,如业务bean,数据源(DataSource)等。在web应用中,其一般通过ContextLoaderListener监听器来加载,通过contextConfigLocation指定配置文件。
  • Servlet WebApplicationContext:这是对J2EE三层架构中的web层进行配置,如控制器(controller)、视图解析器(view resolvers)等相关的bean。通过spring-mvc中提供的DispatchServlet来加载配置,也是通过contextConfigLocation指定配置文件配置文件,默认名称为<servlet-name>-servlet.xml

1、ContextLoaderListener会被优先加载,初始化时,其会根据context-param元素中contextConfigLocation参数指定的配置文件路径,来创建WebApplicationContext实例。 并调用ServletContext的setAttribute方法,将其设置到ServletContext中,属性的key为org.springframework.web.context.WebApplicationContext.ROOT,最后的ROOT字样表明这是一个 Root WebApplicationContext。

2、DispatcherServlet在初始化时,会根据元素中contextConfigLocation参数指定的配置文件路径,来创建Servlet WebApplicationContext。同时,其会调用ServletContext的getAttribute方法来判断是否存在Root WebApplicationContext。如果存在,则将其设置为自己的parent。这就是父子上下文(父子容器)的概念。
父子容器的作用在于,当我们尝试从child context(即:Servlet WebApplicationContext)中获取一个bean时,如果找不到,则会委派给parent context (即Root WebApplicationContext)来查找。

3、如果我们没有通过ContextLoaderListener来创建Root WebApplicationContext,那么Servlet WebApplicationContext的parent就是null,也就是没有parent context。

Root WebApplicationContext创建过程源码分析

ContextLoaderListener用于创建ROOT WebApplicationContext,其实现了ServletContextListener接口的contextInitialized和contextDestroyed方法,在web应用启动和停止时,web容器(如tomcat)会负责回调这两个方法。而创建Root WebApplicationContext就是在contextInitialized中完成的,相关源码片段如下所示:
在这里插入图片描述
可以看到ContextLoaderListener继承了ContextLoader类,WebApplicationContext的创建是在ContextLoader的initWebApplicationContext方法中完成的,关键代码如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Servlet WebApplicationContext创建过程源码分析

其实就是SpringMVC初始化过程。
SpringMVC通过web.xml文件中servlet标签下的DispatcherServlet类完成自身的初始化。

每个servlet在初始化时,会先调用servlte的构造函数(为默认构造函数),接着调用init函数,而DispatcherServlet的init方法在其父类HttpServletBean中。

// DispatcherServlet第一次加载时调用init方法
@Override
public final void init() throws ServletException {
    if (logger.isDebugEnabled()) {
        logger.debug("Initializing servlet '" + getServletName() + "'");
    }
    // Set bean properties from init parameters.
    try {
		/*加载web.xml文件中的servlet标签中的init-param,其中含有springMVC的配置文件的名字和路径
		*若没有,则默认为(servlet-name)-servlet.xml,
		*默认路径为WEF—INF下
		*/
        PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
     	//创建BeanWrapper实例,为DispatcherServlet设置属性
        BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
        ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
        bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
        initBeanWrapper(bw);
     	//把init-param中的参数设置到DispatcherServlet里面去
        bw.setPropertyValues(pvs, true);
    }
    catch (BeansException ex) {
        logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
        throw ex;
    }

    // Let subclasses do whatever initialization they like.
    //该方法在FrameworkServlet中
    initServletBean();

    if (logger.isDebugEnabled()) {
        logger.debug("Servlet '" + getServletName() + "' configured successfully");
    }
}

FrameworkServlet中的initServletBean方法:
在这里插入图片描述

参考:
https://www.cnblogs.com/yaoyiyao/p/7198076.html
https://www.cnblogs.com/jiaguozhilian/p/5819032.html

  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值