Spring:web.xml中的namespace vs contextConfigLocation init参数

Luc*_*uke 57 spring dependency-injection spring-mvc

我正在阅读Spring MVC的文档,我有一个关于init params的问题.如果重要,我正在使用Spring 3.2.contextConfigLocation和命名空间有什么区别?contextConfigLocation是否仅用于指定上下文类可以找到XML定义的文件夹,而namespace属性用于指定文件名?

<servlet>
        <servlet-name>AppServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>WEB-INF</param-value>
        </init-param>
        <init-param>
            <param-name>namespace</param-name>
            <param-value>application-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
Run Code Online (Sandbox Code Playgroud)

它是否正确?它应该使用/WEB-INF/application-context.xml吗?你应该指定路径吗?

inf*_*k01 168

TL; DR

只需contextConfigLocation在需要指定自定义配置文件时设置值即可.这样,您将指定配置文件名及其位置.

namespace本质上是一种替代方法告诉Spring容器上下文加载类什么配置文件来使用.我从不打扰它,但contextConfigLocation只要我需要配置自定义配置文件.

这是我之前的一个Spring项目的示例(为简洁起见,省略了一些配置):

web.xml中

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                            http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <display-name>Spring Web Application example</display-name>

    <!-- Configurations for the root application context (parent context) -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/jdbc/spring-jdbc.xml
            /WEB-INF/spring/security/spring-security-context.xml
        </param-value>
    </context-param>

    <!-- Configurations for the DispatcherServlet application context (child context) -->
    <servlet>
        <servlet-name>spring-mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/spring/mvc/spring-mvc-servlet.xml
            </param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>spring-mvc</servlet-name>
        <url-pattern>/admin/*</url-pattern>
    </servlet-mapping>

</web-app>
Run Code Online (Sandbox Code Playgroud)

答案很长

好的,首先让我们清楚一些重要的时刻.我们正在处理两种类型的上下文:

  1. 根上下文(父)
  2. 单个servlet上下文(子)

引用来自Spring Framework API(编写本文时的版本3.2.2)的WebApplicationContext(强调我的):

与通用应用程序上下文一样,Web应用程序上下文是分层的.每个应用程序都有一个根上下文,而应用程序中的每个servlet(包括MVC框架中的调度程序servlet)都有自己的子上下文.

此处:上下文层次结构:

例如,如果您正在开发Spring MVC Web应用程序,则通常会通过Spring的ContextLoaderListener加载根WebApplicationContext,通过Spring的DispatcherServlet加载子WebApplicationContext.这将生成父子上下文层次结构,其中共享组件和基础结构配置在根上下文中声明,并由特定于Web的组件在子上下文中使用.

这里:17.2 DispatcherServlet:

Spring中的ApplicationContext实例可以作用域.在Web MVC框架中,每个DispatcherServlet都有自己的WebApplicationContext,它继承了根WebApplicationContext中已定义的所有bean.可以在特定于servlet的作用域中重写这些继承的bean,并且可以为给定的Servlet实例定义新的作用域特定的bean.


现在让我们看一下根应用程序上下文配置.这是一个例子:
web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                            http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/daoContext.xml
            /WEB-INF/spring/applicationContext.xml
        </param-value>
    </context-param>
</web-app>
Run Code Online (Sandbox Code Playgroud)


从官方Spring文档(强调我的):
5.14.4 Web应用程序的便捷ApplicationContext实例化:

您可以使用例如ContextLoader以声明方式创建ApplicationContext实例.当然,您也可以使用其中一个ApplicationContext实现以编程方式创建ApplicationContext实例.

您可以使用ContextLoaderListener注册ApplicationContext (请参阅上面的示例)

侦听器检查contextConfigLocation参数.如果参数不存在,则侦听器将/WEB-INF/applicationContext.xml用作默认值.当参数确实存在时,侦听器使用预定义的分隔符(逗号,分号和空格)分隔String,并将值用作将搜索应用程序上下文的位置.还支持Ant样式的路径模式.名称以"Context.xml"结尾的所有文件的/WEB-INF/*Context.xml,驻留在"WEB-INF"目录中,/ WEB-INF/**/*Context.xml表示所有文件这些文件位于"WEB-INF"的任何子目录中.


Spring配置通常分为多个文件.它更合乎逻辑,更方便,特别是在大型项目中.在我们的示例中,我们在自定义位置明确定义了两个配置XML文件:daoContext.xmlapplicationContext.xml : /WEB-INF/spring/. 同样,如果我们没有定义contextConfigLocation,ContextLoaderListener将尝试找到默认的配置文件:/WEB-INF/applicationContext.xml.

注:
根上下文是可选的.另请参阅此答案:https://stackoverflow.com/a/7451389/814702

因此,如果默认/WEB-INF/applicationContext.xml配置文件不符合您的需求,请使用ContextLoaderListener以及<context-param> contextConfigLocation,您可以在其中定义自定义配置文件以定义根应用程序上下文.


接下来让我们看一下个人(子)应用程序上下文.从官方Spring文档(强调我的):
17.2 DispatcherServlet

在初始化DispatcherServlet时,Spring MVC
Web应用程序的WEB-INF目录查找名为[servlet-name] -servlet.xml的文件,并创建在那里定义的bean,覆盖使用相同名称定义的任何bean的定义在全球范围内.

请考虑以下DispatcherServlet Servlet配置(在web.xml文件中):

<web-app>

    <servlet>
        <servlet-name>golfing</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>golfing</servlet-name>
        <url-pattern>/golfing/*</url-pattern>
    </servlet-mapping>

</web-app>
Run Code Online (Sandbox Code Playgroud)


关于contextConfigLocation和命名空间

从文档(强调我的):

使用上面的Servlet配置,您需要
/WEB-INF/golfing-servlet.xml在应用程序中调用一个文件; 此文件将包含所有Spring Web MVC特定组件(bean).您可以通过Servlet初始化参数更改此配置文件的确切位置(有关详细信息,请参阅下文).
...
您可以通过将Servlet初始化参数(init-param元素)添加到web.xml文件中的Servlet声明来自定义各个DispatcherServlet实例.有关支持的参数列表,请参阅下表.

  • contextClass:实现WebApplicationContext的类,它实例化此Servlet使用的上下文.默认情况下,使用XmlWebApplicationContext.

  • contextConfigLocation:传递给上下文实例(由contextClass指定)的字符串,用于指示可以在何处找到上下文.该字符串可能包含多个字符串(使用逗号作为分隔符)以支持多个上下文.如果多个上下文位置的bean定义了两次,则最新位置优先.

  • namespace:WebApplicationContext的命名空间.默认为[servlet-name] -servlet.


现在让我们研究相关类的API文档.DispatcherServlet类扩展了抽象类FrameworkServlet.来自FrameworkServlet API文档(强调我的):

将"contextConfigLocation"servlet init-param传递给上下文实例,将其解析为可能由多个逗号和空格分隔的多个文件路径,例如
"test-servlet.xml,myServlet.xml".如果没有明确指定,则上下文实现应该从servlet的命名空间构建一个默认位置.

默认命名空间是"'servlet-name'-servlet",例如"test-servlet"用于servlet-name"test"(通过XmlWebApplicationContext导致"/WEB-INF/test-servlet.xml"默认位置).也可以通过"namespace"servlet init-param显式设置命名空间.

这是FrameworkServlet源代码的摘录:
FrameworkServlet.java

....
/**
* Suffix for WebApplicationContext namespaces. If a servlet of this class is
* given the name "test" in a context, the namespace used by the servlet will
* resolve to "test-servlet".
*/
public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";
....
Run Code Online (Sandbox Code Playgroud)


FrameworkServlet 的默认上下文类是XmlWebApplicationContext.从XmlWebApplicationContext API文档(强调我的):

默认情况下,配置将从"/WEB-INF/applicationContext.xml"获取根上下文,而"/WEB-INF/test-servlet.xml"获取具有命名空间"test-servlet"的上下文(如对于具有servlet-name"test"的DispatcherServlet实例.

可以通过ContextLoader的"contextConfigLocation"context-param和FrameworkServlet的servlet init-param覆盖配置位置默认值.配置位置可以表示具体文件,如"/WEB-INF/context.xml"或Ant样式模式,如"/WEB-INF/*-context.xml"(有关模式详细信息,请参阅PathMatcher javadoc).

使用的覆盖默认配置位置contextConfigLocation与上面的根应用程序上下文示例相同.

至于覆盖默认命名空间,有一些重要的时刻.设置新的命名空间时,请不要在其前面/WEB-INF添加,也不要追加.xml到它.如果我们查看XmlWebApplicationContext类的源文件,可以发现原因:
XmlWebApplicationContext.java

...

/** Default config location for the root context */
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

/** Default prefix for building a config location for a namespace */
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";

/** Default suffix for building a config location for a namespace */
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";

...

/**
* The default location for the root context is "/WEB-INF/applicationContext.xml",
* and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet"
* (like for a DispatcherServlet instance with the servlet-name "test").
*/
@Override
protected String[] getDefaultConfigLocations() {
    if (getNamespace() != null) {
        return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
    }
    else {
        return new String[] {DEFAULT_CONFIG_LOCATION};
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,源代码说明了一切.


指定自定义命名空间的示例

web.xml中

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                            http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">


    <!-- Configurations for the DispatcherServlet application context (child context) -->
    <servlet>
        <servlet-name>spring-mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>namespace</param-name>
            <param-value>spring/mvc/spring-mvc</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>spring-mvc</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>
Run Code Online (Sandbox Code Playgroud)

结果是,不是使用默认命名空间来构造配置文件的路径,否则/WEB-INF/spring-mvc-servlet.xml容器将寻找/WEB-INF/spring/mvc/spring-mvc.xml.

注意:
以上与设置自定义命名空间相关的说明适用于默认的XmlWebApplicationContext上下文类.可以指定一个替代类,如AnnotationConfigWebApplicationContext,因此会有一些特殊的时刻.


结论

(IMHO)使用contextConfigLocation参数来定义自定义配置文件更容易,无论是根应用程序上下文还是单个上下文.唯一的区别是对于<context-param><web-app>元素中使用的根应用程序上下文,但不在特定的servlet中(也不要忘记监听器类).对于子上下文,您使用<init-param>嵌套在每个特定servlet<servlet>元素内部.请参阅本文开头的示例配置(web.xml).

额外资源(如上所述还不够:-)):

  • 很棒的解释.你是天才. (2认同)