小编典典

Spring:Web.xml中的命名空间与contextConfigLocation初始化参数

spring

我正在阅读Spring MVC的文档,并且对初始化参数有疑问。如果有关系,我正在使用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>

这个对吗?是否应使用/WEB-INF/application-context.xml?并且您应该指定路径吗?


阅读 545

收藏
2020-04-13

共1个答案

小编典典

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>

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

  • 根上下文(父级)
  • 单个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。这些继承的bean可以在servlet特定的作用域中被覆盖,并且你可以在给定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>

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

你可以使用例如ContextLoader 声明性地创建ApplicationContext实例。当然,你也可以使用ApplicationContext实现之一以编程方式创建ApplicationContext实例。

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

侦听器检查contextConfigLocation参数。如果参数不存在,那么侦听器将使用/WEB-INF/applicationContext.xml作为默认值。当该参数确实存在时,侦听器将使用预定义的定界符(逗号,分号和空格)来分隔String并将这些值用作将在其中搜索应用程序上下文的位置。还支持蚂蚁风格的路径模式。对于所有名称以“ Context.xml”结尾的文件(位于“ WEB-INF”目录中)和/WEB-INF//Context.xml而言,示例为/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>

关于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初始化参数传递给上下文实例,将其解析为可能由多个逗号和空格分隔的多个文件路径,例如
“ test-servlet.xml,myServlet.xml”。如果未明确指定,则上下文实现应从servlet的命名空间构建默认位置。

默认名称空间是“’servlet-name’-servlet”,例如servlet-name“ test”的“ test-servlet”(通过XmlWebApplicationContext指向“ /WEB-INF/test-servlet.xml”默认位置)。命名空间也可以通过“命名空间” 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";
....

FrameworkServlet 的默认上下文类是XmlWebApplicationContext。从XmlWebApplicationContext API文档(重点是我的):

默认情况下,配置将从“ /WEB-INF/applicationContext.xml”获取根上下文,从“ /WEB-INF/test-servlet.xml”获取具有名称空间“ test-servlet”的上下文(例如Servlet名称为“ test”的DispatcherServlet实例)。

可以通过ContextLoader的“ contextConfigLocation”上下文参数和FrameworkServlet的servlet init-param覆盖配置位置的默认值。配置位置可以表示诸如“ /WEB-INF/context.xml”之类的具体文件,也可以表示诸如“ /WEB-INF/*-context.xml”之类的Ant样式的模式(有关模式的详细信息,请参见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};
    }
}

如你所见,源代码说明了一切。

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

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>

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

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

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

2020-04-13