Spring XML文件configuration层次结构的帮助/解释

当我第一次开始学习Spring时,事情是在applicationContext.xml文件中configuration的。 然后,当我开始阅读专门针对更新版本的Spring的书籍时,他们都已经在独立的XML文件(如myapp-servlet-xml,myapp-security.xml,myapp-service.xml等)中完成了configuration,在web.xml文件中configuration一个contextConfigLocation。 所以,例如,我一直遵循的代码有这个,因为它的contextConfigLocation:

<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/myapp-servlet.xml /WEB-INF/myapp-data.xml </param-value> </context-param> 

无论如何,最近我遇到了一个configuration问题(StackOverflow的帮助人员帮我弄清楚了),这是由于这种分离。 没有applicationContext.xml文件的这些书籍的例子,后来我尝试添加自动扫描和注释到应用程序,这引起了问题。 我试着把所有东西都移到applicationContext.xml中,并且废除了其他文件,解决了这个问题。 没有别的改变,我只是把一切都放在applicationContext.xml中。

所以,这个以及其他人的评论让我明白,即使你没有创build一个applicationContext.xml,它仍然被使用,它是某种configuration层次结构的顶层。 我希望别人能向我解释这一切是如何运作的,因为我没有在任何地方find任何解释。

例如,如果我将某些上下文:component-scan标记放入applicationContext.xml下的configuration文件中,可能会导致某些类无法扫描。 那种性质的东西。 我不明白优先顺序,以及在哪里可以确定应用程序广泛等等。 如果有人能够清楚地解释它或者指出一个解释它的资源,我将不胜感激,谢谢。 希望我所问的是有道理的。

除了名称为Spring的默认configuration文件外,没有什么特别的名字叫“applicationContext.xml”。 使用名为“dog.xml”,“cat.xml”和“alien.xml”的一个文件或多个文件将以完全相同的方式工作。 您遇到的麻烦来自同时使用多个ApplicationContext,而不是来自多个XML文件。 最近我回答了一些由于不理解这些概念而导致问题的人的问题。 看看这些答案,看看你还有什么问题:

在父上下文中声明Spring Bean与子上下文

Spring-MVC:什么是“上下文”和“命名空间”?

编辑:为了回应你的新问题:

我在我的servlet.xml中有一个<context:component-scan base-package="com.myapp"/>标签。

我猜这个“servlet.xml”文件被命名为foo-servlet.xml ,其中在web.xml中configuration的DispatcherServlet被命名为“foo”,就像

 <servlet> <servlet-name>foo</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> 

按照惯例,当这个DispatcherServlet启动时,它将创build一个新的ApplicationContext,它由从servlet-name派生的文件foo-servlet.xmlconfiguration。 现在,由于您将context:component-scan放在那里,它将recursion扫描给定的包,并为所有带注释的类创buildbean。 你给它的包, com.myapp ,看起来就像是你的整个应用的基础包,所以Spring将从你的应用中的所有注解的类(包括数据访问的类)创buildbean,在这个ApplicationContext中关联到DispatcherServlet的。 通常情况下,这个上下文应该只有视图层的东西和bean,直接支持DispatcherServlet,所以这是一个错误的configuration。

在我的data.xml文件中,我有数据源bean,就是这样。 没有其他的豆,其他一切都是自动assembly和注释。

据推测,这个“data.xml”文件是你在contextConfigLocation context-param中列出的文件。 假设你还将ContextLoaderListener添加到你的web.xml

 <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 

那么该文件将被用来创build第二个ApplicationContext – 根上下文。 这是这个听众所做的。 请注意,它实际上是从contextConfigLocation列出的所有文件构build的上下文,如果您还在该列表中包含了“servlet.xml”,那么您已经加载了该configuration两次:在根上下文中以及在上下文中与DipatcherServlet相关联。 希望您现在看到XMLconfiguration文件和它们configuration的ApplicationContext之间是如何区分的。 同一个XML文件可以很容易地用来configuration两个不同的上下文。 这样做是否正确是另一个问题。 在这个特殊的情况下,事实并非如此。

我所描述的这两个上下文的顺序实际上是向后的。 我只是跟随你的描述。 作为ServletContextListener的ContextLoaderListener将始终在任何servlet启动之前执行。 这意味着根上下文首先被创build,而另一个上下文被创build。 这在devise上是这样的,当DispatcherServlet创build它的上下文时,它可以将该上下文添加为根上下文的子元素。 我在其他post中描述了这种关系。 这个最重要的效果就是根环境中的bean可以通过DispatcherServlet的上下文来使用。 这也适用于自动assembly关系。 这很重要,因为DispatcherServlet 在它所需的bean的相关上下文中查找,就像控制器实例一样。 但是,你的控制器显然必须连接支持的豆子。 因此,传统上,控制器位于DispatcherServlet的上下文中,并且支持的bean位于根上下文中。

然后我试图添加@Transacational到我的服务bean,它不会持续。

为了使@Transactional正常工作,必须将<tx:annotation-driven/>标签包含在注释bean所在的ApplicationContext的configuration中。 诀窍是搞清楚“它住哪里”的部分。 小孩的豆可以在父上下文中覆盖bean。 因此,我只是在这里猜测 – 如果你像上面描述的那样将所有的bean加载到DispatcherServlet上下文中,但是将<tx:annotation-driven/>放在根上下文中,那么你可能在根上下文中有一个bean这是正确的事务性的,但它不是正在使用的,因为重复与父/子层次结构中的servlet“更接近”,并且它所在的上下文没有得到<tx:annotation-driven/>configuration。

当我更改servlet上下文:component-scan标记而不是指向com.myapp.web,然后将一个上下文:component-scan标记添加到data.xml文件时,一切正常。

它在某种程度上还取决于你在哪个ApplicationContexts中包含哪些configuration文件,但是至less我可以这么说,你从DispatcherServlet的上下文中删除了很多导致问题的bean。 特别是,根环境中正确configuration的@Transactional bean将不再被子上下文中的bean所影响,并且会被注入到控制器中,所以你的持久化的东西就可以工作了。

所以…主要的东西是你有两个相关的ApplicationContext。 你必须保持意识到这一点,并保持控制哪些豆在哪些情况下。

这是否涵盖一切?