假设我有一个 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文件。一个是我的整个应用程序的通用,而另一个是特定于&#34; my-servlet&#34; servlet的。对于只有一个servlet映射的设置,这没有意义。但是,我的项目有多个servlet映射,每个都有特定的Spring设置。
我的问题: Spring会首先加载哪个contextConfigLocation?它是generalApplicationContext.xml还是specialApplicationContext.xml?更重要的是,装载的顺序是否重要?从我的调试工作来看,它似乎很明显,因为当我将一些独立的Spring配置从一个文件移动到另一个文件时,我得到了不同的错误。
NB:对于多个servlet映射是否使用多个弹簧配置是一个很好的做法值得商榷。使用XML配置而不是新的Java配置也是如此。但这不是我在这里要问的问题。让我们试着关注我的主要问题。
答案 0 :(得分:21)
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>
是的,加载顺序很重要。因为在加载父上下文时,必须满足所有必需的依赖项。
答案 1 :(得分:8)
以下部分加载上下文文件并创建 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>
答案 2 :(得分:7)
实际拥有Spring调试日志的更好方法是告诉您自己的顺序。
如果你想进入代码,你也可以看一下org.springframework.web.servlet.FrameworkServlet
(DispatcherServlet
扩展这个类)只需在你首选的日志框架中启用logger "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
答案 3 :(得分:3)
如果您在web.xml中有 ContextLoaderListener ,那么Spring将首先加载 generalApplicationContext.xml 。这将创建bean并为它们提供所有Servlet和过滤器。这个xml应该有你的应用程序中使用的公共类bean。
以后的spring容器将加载 specificApplicationContext.xml ,因为您在servlet配置中启动时加载。如果您未在启动时指定负载,则 specificApplicationContext.xml 将在第一个请求带到特定网址模式的应用程序时加载。< / p>
当您将springconfig从一个配置移动到另一个配置时,这是一个问题,这将改变容器的应用程序资源可用性。如果在generalApplicationContext.xml中指定Controller bean,并且您没有在specificApplicationContext.xml中指定它们,那么DispatcherServlet将找不到映射,因此您将看到404错误。
如果要按需创建一些bean对象,可以再创建一个servlet-config来加载特定的specificConfigurationFile2.xml,并映射到url-pattern。