Spring Servlet 项目的 web.xml 中加载 contextConfigLocation 的顺序
Posted
技术标签:
【中文标题】Spring Servlet 项目的 web.xml 中加载 contextConfigLocation 的顺序【英文标题】:Order of loading contextConfigLocation in web.xml of Spring Servlet project 【发布时间】:2015-02-16 19:53:39 【问题描述】:假设我有一个 Spring Java 项目,并且我正在尝试将其配置为 Web 服务器 servlet。这是 web.xml 文件的精简版:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/generalApplicationContext.xml
</param-value>
</context-param>
<servlet>
<servlet-name>my-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/specificApplicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>my-servlet</servlet-name>
<url-pattern>/foo/*</url-pattern>
</servlet-mapping>
这里要注意的关键是我已经指定了两个要加载的 XML 文件。一个对我的整个应用程序是通用的,而另一个特定于“my-servlet”servlet。对于只有一个 servlet 映射的设置,这是没有意义的。但是,我的项目有多个 servlet 映射,每个映射都有特定的 Spring 设置。
我的问题: Spring 将首先加载哪个 contextConfigLocation?它是generalApplicationContext.xml 还是specificApplicationContext.xml?更重要的是,加载顺序是否重要?从我的调试工作来看,它似乎确实如此,因为当我将一些独立的 Spring 配置从一个文件移动到另一个文件时,我得到了不同的错误。
注意: 对多个 servlet 映射使用多个 spring 配置是否是一种好做法是值得商榷的。使用 XML 配置而不是新的 Java 配置也是如此。但这不是我想在这里问的。让我们试着专注于我的主要问题。
【问题讨论】:
你在 DispatcherServlet 中声明的那个我不确定,<load-on-startup>1</load-on-startup>
因为这个我认为。
要完全加载 contextConfigLocation
/ generalApplicationContext.xml
,您必须有一个 ContextLoaderListener
- 请参阅 shazin 的答案。为了更深入地了解什么是有用的,请参阅此问题和答案:***.com/questions/9016122/…
NB是什么意思?
【参考方案1】:
有什么更好的方法让 Spring 调试日志告诉你自己的顺序。
如果您想进入代码,您还可以查看org.springframework.web.servlet.FrameworkServlet
(DispatcherServlet
扩展了此类)只需启用记录器"org.springframework.web.servlet"
以在您首选的日志记录框架中调试级别
以下是日志的典型外观 - 显然,根上下文首先加载并设置为上下文层次结构的父级 - 接下来加载 servlet 上下文。
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/generalApplicatonContext.xml]
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 256 ms
DEBUG: org.springframework.web.servlet.DispatcherServlet - Initializing servlet 'my-servlet'
INFO :Initializing Spring FrameworkServlet 'appServlet'
INFO : org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'my-servlet': initialization started
DEBUG: org.springframework.web.servlet.DispatcherServlet - Servlet with name 'appServlet' will try to create custom WebApplicationContext context of class 'org.springframework.web.context.support.XmlWebApplicationContext', using parent context [Root WebApplicationContext: startup date [Fri May 15 17:08:24 IST 2015]; root of context hierarchy
DEBUG: Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/specificApplicationContext.xml
【讨论】:
这是否意味着“specificApplicationContext.xml”应该只有与@controllers和view Resolvers相关的配置?而“generalApplicatonContext.xml”将保存应用程序级别的配置,如事务管理器和服务bean以及石英调度程序,我的意思是所有控制器都可以使用的配置,为什么我们不能在“generalApplicatonContext.xml”中进行所有配置?【参考方案2】:如果您的 web.xml 中有 ContextLoaderListener,spring 将首先加载 generalApplicationContext.xml。这将创建 bean 并为它们提供所有 Servlet 和过滤器。这个 xml 应该有你的应用程序中使用的公共类,bean。
稍后 spring 容器将加载 specificApplicationContext.xml,因为您在 servlet 配置中已加载启动。如果您未指定启动时的负载,则此 specificApplicationContext.xml 将在 first request 以特定 url-pattern 到达您的应用程序时加载。
作为您的问题,当您将 springconfig 从一个配置移动到另一个配置时,这将改变容器的应用程序资源可用性。如果您在 generalApplicationContext.xml 中指定了 Controller bean 而您没有在 specificApplicationContext.xml 中指定它们,那么您的 DispatcherServlet 将找不到映射,因此您将看到 404 错误。
如果您想按需创建一些 bean 对象,您可以再创建一个 servlet-config 来加载特定的配置文件 2.xml,并映射到 url-pattern。
【讨论】:
【参考方案3】:以下部分加载上下文文件并创建 ApplicationContext。例如,此上下文可能包含组件,例如中间层事务服务、数据访问对象或您可能希望在应用程序中使用(和重用)的其他对象。每个应用程序将有一个应用程序上下文。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/generalApplicationContext.xml
</param-value>
</context-param>
另一个上下文是WebApplicationContext,它是应用程序上下文的子上下文。在 Spring Web 应用程序中定义的每个 DispatcherServlet
都会有一个关联的 WebApplicationContext
。 WebApplicationContext
的初始化如下:
<servlet>
<servlet-name>my-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/specificApplicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
更多详情请参考this和this
【讨论】:
您所写的在大多数情况下都是正确的,但在这一次中则不然,因为ecbrodie
在他的xml 中没有ContextLoaderListener
或者他在问题中无意中省略了它。
我没有发布完整的 web.xml。我一有机会就会这样做。
@ankur 你的父 ApplicationContext 也是 WebApplicationContext 的实例。【参考方案4】:
generalApplicationContext.xml
将首先加载,因为它是 ApplicationContext
与 ContextLoaderListener
一起加载
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/generalApplicationContext.xml
</param-value>
</context-param>
specificApplicationContext.xml
实际上是上面加载的generalApplicationContext.xml
的子上下文,它将是WebApplicationContext
<servlet>
<servlet-name>my-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/specificApplicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>my-servlet</servlet-name>
<url-pattern>/foo/*</url-pattern>
</servlet-mapping>
是的,加载顺序很重要。因为在加载父上下文时,必须满足所有必需的依赖项。
【讨论】:
你是如何将ApplicationContext
和WebApplicationContext
命名为的?
我知道WebApplicationContext
是ApplicationContext
的子类型。但是我想知道ContextLoaderListener
究竟是什么,ApplicationContext
或WebApplicationContext
。如果它创建ApplicationContext
实例,它肯定不等同于WebApplicationContext
,因为前者不提供后者的功能。是不是就像,准确地说,ContextLoaderListener
创建了WebApplicationContext
,它也提供了ApplicationContext
的功能,是它的子类型? [继续...]
[...continued] This answer 表示它同时创建了 ApplicationContext
和 WebApplicationContext
。 ? 现在尝试从source 了解它到底做了什么。但它没有任何意义......
[...continued] 好的,看看source(也是它的supertype),它似乎创建了WebApplicationContext
。解释这个话题的文章说ApplicationContext
是为了方便(或者隐含地假设读者会知道我们总是说WebApplicationContext
?)。
[...contined 4] 是不是就像ContextLoaderListener
创建的WebApplicaionContext
是usually online articles refer 作为“root” WebApplicationContext
一样,只是为了将其与 DispatcherServlet
创建的 WebApplicationContext
s 区分开来?以上是关于Spring Servlet 项目的 web.xml 中加载 contextConfigLocation 的顺序的主要内容,如果未能解决你的问题,请参考以下文章
Allocate exception for servlet XXX 基本异常