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

标签 spring spring-mvc dependency-injection

我正在阅读 Spring MVC 的文档,我有一个关于 init 参数的问题。如果重要的话,我正在使用 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 吗?你应该指定路径吗?

最佳答案

TL; 博士

只需为 contextConfigLocation 设置值每当您需要指定自定义配置文件时。通过这种方式,您将同时指定配置文件名及其位置。

namespace本质上是另一种方式 告诉 Spring 容器上下文加载器类使用什么配置文件。我从不打扰它,只是使用 contextConfigLocation每当我需要配置自定义配置文件时。

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

网页.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>

长答案

好的,首先让我们弄清楚一些重要的时刻。我们正在处理两种类型的上下文:
  • 根上下文 ( parent )
  • 单个 servlet 上下文 ( child )

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

    Like generic application contexts, web application contexts are hierarchical. There is a single root context per application, while each servlet in the application (including a dispatcher servlet in the MVC framework) has its own child context.



    也在这里:Context hierarchies :

    For example, if you are developing a Spring MVC web application you will typically have a root WebApplicationContext loaded via Spring's ContextLoaderListener and a child WebApplicationContext loaded via Spring's DispatcherServlet. This results in a parent-child context hierarchy where shared components and infrastructure configuration are declared in the root context and consumed in the child context by web-specific components.



    在这里:17.2 The DispatcherServlet :

    ApplicationContext instances in Spring can be scoped. In the Web MVC framework, each DispatcherServlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext. These inherited beans can be overridden in the servlet-specific scope, and you can define new scope-specific beans local to a given Servlet instance.



    现在让我们看看 根应用程序上下文 配置。下面是一个例子:
    网页.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 Convenient ApplicationContext instantiation for web applications :

    You can create ApplicationContext instances declaratively by using, for example, a ContextLoader. Of course you can also create ApplicationContext instances programmatically by using one of the ApplicationContext implementations.

    You can register an ApplicationContext using the ContextLoaderListener (see the example above)

    The listener inspects the contextConfigLocation parameter. If the parameter does not exist, the listener uses /WEB-INF/applicationContext.xml as a default. When the parameter does exist, the listener separates the String by using predefined delimiters (comma, semicolon and whitespace) and uses the values as locations where application contexts will be searched. Ant-style path patterns are supported as well. Examples are /WEB-INF/*Context.xml for all files with names ending with "Context.xml", residing in the "WEB-INF" directory, and /WEB-INF/**/*Context.xml, for all such files in any subdirectory of "WEB-INF".



    Spring 配置经常被拆分到多个文件中。更合乎逻辑和方便,尤其是在大型项目中。在我们的示例中,我们在自定义位置明确定义了两个配置 XML 文件:daoContext.xml 和 applicationContext.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 The DispatcherServlet

    Upon initialization of a DispatcherServlet, Spring MVC looks for a file named
    [servlet-name]-servlet.xml in the WEB-INF directory
    of your web application and creates the beans defined there, overriding the definitions of any beans defined with the same name in the global scope.

    Consider the following DispatcherServlet Servlet configuration (in the web.xml file):



    <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 和命名空间

    从文档(强调我的):

    With the above Servlet configuration in place, you will need to have a file called
    /WEB-INF/golfing-servlet.xml in your application; this file will contain all of your Spring Web MVC-specific components (beans). You can change the exact location of this configuration file through a Servlet initialization parameter (see below for details).
    ...
    You can customize individual DispatcherServlet instances by adding Servlet initialization parameters (init-param elements) to the Servlet declaration in the web.xml file. See the following table for the list of supported parameters.

    • contextClass: Class that implements WebApplicationContext, which instantiates the context used by this Servlet. By default, the XmlWebApplicationContext is used.

    • contextConfigLocation: String that is passed to the context instance (specified by contextClass) to indicate where context(s) can be found. The string consists potentially of multiple strings (using a comma as a delimiter) to support multiple contexts. In case of multiple context locations with beans that are defined twice, the latest location takes precedence.

    • namespace: Namespace of the WebApplicationContext. Defaults to [servlet-name]-servlet.



    现在让我们研究相关类的 API 文档。类(class)DispatcherServlet扩展抽象类 FrameworkServlet .来自 FrameworkServlet API 文档(重点是我的):

    Passes a "contextConfigLocation" servlet init-param to the context instance, parsing it into potentially multiple file paths which can be separated by any number of commas and spaces, like
    "test-servlet.xml, myServlet.xml". If not explicitly specified, the context implementation is supposed to build a default location from the namespace of the servlet.

    The default namespace is "'servlet-name'-servlet", e.g. "test-servlet" for a servlet-name "test" (leading to a "/WEB-INF/test-servlet.xml" default location with XmlWebApplicationContext). The namespace can also be set explicitly via the "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";
    ....
    

    FrameworkServlet 的默认上下文类是 XmlWebApplicationContext .来自 XmlWebApplicationContext API 文档(重点是我的):

    By default, the configuration will be taken from "/WEB-INF/applicationContext.xml" for the root context, and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet" (like for a DispatcherServlet instance with the servlet-name "test").

    The config location defaults can be overridden via the "contextConfigLocation" context-param of ContextLoader and servlet init-param of FrameworkServlet. Config locations can either denote concrete files like "/WEB-INF/context.xml" or Ant-style patterns like "/WEB-INF/*-context.xml" (see PathMatcher javadoc for pattern details).



    使用 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};
        }
    }
    

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

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

    网页.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)。

    其他资源(好像以上还不够:-)):
  • Spring Framework Reference Documentation
  • Difference between applicationContext.xml and spring-servlet.xml in Spring
  • What is the difference between ApplicationContext and WebApplicationContext in Spring MVC?
  • Spring-MVC: What are a “context” and “namespace”?
  • 关于Spring:web.xml 中的命名空间与 contextConfigLocation 初始化参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15818047/

    相关文章:

    java - 如何在Spring Tool Suite中生成hibernate配置文件?

    java - SpringMVC发送JSON数据到服务器(java)

    c# - 替换 ASP.NET Core 中中间件的激活器

    Spring:在同一个类中定义和连接一个 bean

    java - Spring Data Rest - 如何从页面中删除元素?

    java - 是否可以在运行时指定上下文属性占位符

    java - Spring MVC : How to return custom 404 errorpages?

    java - Spring security spring webflow 如何使用用户角色成功登录页面后重定向?

    java - 如何使用 Spring @Configuration 覆盖导入的资源?

    c# - 你如何在工厂中实现构造函数注入(inject)?