59

我正在阅读 Spring MVC 的文档,并且对 init 参数有疑问。如果重要的话,我正在使用 Spring 3.2。contextConfigLocation 和命名空间有什么区别?contextConfigLocation 是否仅用于指定上下文类可以找到 XML 定义的文件夹,而命名空间属性用于指定文件名?

<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 吗?你应该指定路径吗?

4

3 回答 3

174

TL;博士

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>

长答案

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

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

引用WebApplicationContext的 Spring Framework API(撰写本文时为 3.2.2 版) (强调我的):

与通用应用程序上下文一样,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 作为默认值。当参数确实存在时,侦听器使用预定义的分隔符(逗号、分号和空格)分隔字符串,并将值用作将搜索应用程序上下文的位置。也支持 Ant 样式的路径模式。示例是 /WEB-INF/*Context.xml 用于名称以“Context.xml”结尾的所有文件,位于“WEB-INF”目录中,/WEB-INF/**/*Context.xml 用于所有此类文件位于“WEB-INF”的任何子目录中。


Spring 配置经常被拆分为多个文件。它更符合逻辑和方便,尤其是在大型项目中。在我们的示例中,我们在自定义位置显式定义了两个配置 XML 文件: daoContext.xmlapplicationContext.xml/WEB-INF/spring/:。同样,如果我们没有定义contextConfigLocationContextLoaderListener将尝试定位默认配置文件:/WEB-INF/applicationContext.xml.

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

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


接下来让我们看看单个(子)应用程序上下文。来自官方 Spring 文档(重点是我的):
17.2 The 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 init-param 传递给上下文实例,将其解析为可能的多个文件路径,这些路径可以用任意数量的逗号和空格分隔,例如
“test-servlet.xml,myServlet.xml”。如果没有明确指定,上下文实现应该从 servlet 的命名空间构建一个默认位置

默认命名空间是“'servlet-name'-servlet”,例如“test-servlet”表示servlet-name“test”(导致带有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”或 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};
    }
}

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


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

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,因此会有一些特殊的时刻。


结论

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

其他资源(好像以上还不够:-)):

于 2013-04-05T03:04:12.220 回答
4

我认为 LuckyLuke 的答案有很多有用的信息,但它没有回答这个问题。特别是“namespace”和“contextConfigLocation”参数如何协同工作?

我唯一能找到具体答案的地方是源代码:

  • 命名空间参数设置用于构建默认上下文配置位置的自定义命名空间
  • contextConfigLocation参数显式设置上下文配置位置,而不是依赖于从命名空间构建的默认位置
于 2013-08-14T20:05:12.230 回答
3

contextConfigLocation 和命名空间有什么区别? contextConfigLocation 用于指定 spring 配置文件的路径,这意味着它们将被初始化。namespace 用于指定 Spring MVC 的 DispatcherServlet 的路径和名称。默认是[Dispatcher_name]-servlet.xml,这里是一个例子:

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>namespace</param-name>
        <param-value>config/spring-mvc</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

Spring 将通过路径搜索要用作 mvc 配置的文件/WEB-INF/config/spring-mvc.xml
contextConfigLocation 是否仅用于指定上下文类可以找到 XML 定义的文件夹

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/config/app-*.xml</param-value>
</context-param>

上面的代码表明,当应用程序启动时,Spring 将加载 WEB-INF/config 目录中所有名称以 'app-' 开头并以 '.xml' 结尾的文件。

它应该使用 /WEB-INF/application-context.xml 吗?你应该指定路径吗?
通过上面的例子我们可以知道,在配置Spring的时候我们需要指定完整路径和通用文件名,而只有SpringMVC的时候我们应该指定路径(如果它位于一个目录中,不包括WEB-INF目录)和名称(不包括扩展名)。
希望能帮到你:)

于 2013-04-04T18:45:43.477 回答