【问题标题】:Spring XML file configuration hierarchy help/explanationSpring XML 文件配置层次结构帮助/说明
【发布时间】:2011-12-08 03:01:52
【问题描述】:

当我第一次开始学习 Spring 时,在 applicationContext.xml 文件中进行了配置。然后,当我开始专门阅读有关 Spring 更新版本的书籍时,他们都在单独的 XML 文件中完成了配置,例如 myapp-servlet-xml、myapp-security.xml、myapp-service.xml 等,通过在 web.xml 文件中配置 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>

无论如何,最近我遇到了一个配置问题(StackOverflow 的乐于助人的人帮我解决了这个问题),这是由于这种分离造成的。这些书中的示例没有 applicationContext.xml 文件,后来当我尝试向应用程序添加自动扫描和注释时,这导致了问题。我尝试将所有内容移入 applicationContext.xml 并删除其他文件,从而解决了问题。没有其他变化,我只是把所有东西都放在 applicationContext.xml 中。

因此,这与来自其他人的 cmets 一起让我有点理解,即使您不创建 applicationContext.xml,它仍然在使用,并且它是某种配置层次结构的顶层。我希望其他人可以向我解释这一切是如何工作的,因为我在任何地方都没有遇到过任何解释。

例如,如果我将某些 context:component-scan 标签放入 applicationContext.xml 下的配置文件中,可能会导致某些类无法被扫描。那种性质的东西。我不明白优先级以及必须去哪里才能确保它在应用程序范围内被看到等等。如果有人可以清楚地解释它或将我指向解释它的资源,我将不胜感激,谢谢。希望我的问题是有道理的。

【问题讨论】:

    标签: spring


    【解决方案1】:

    名为“applicationContext.xml”的文件没有什么特别之处,只是 Spring 倾向于将其命名为默认配置文件。使用一个名为该文件的文件或多个名为“dog.xml”、“cat.xml”和“alien.xml”的文件的工作方式完全相同。您遇到的麻烦来自同时使用多个 ApplicationContexts,而不是来自拥有多个 XML 文件。我最近回答了一些因不理解这些概念而遇到问题的人提出的问题。查看这些答案,看看您还有什么问题:

    Declaring Spring Bean in Parent Context vs Child Context

    Spring-MVC: What are a "context" and "namespace"?

    编辑:回答您的新问题:

    我的 servlet.xml 中有一个 &lt;context:component-scan base-package="com.myapp"/&gt; 标记。

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

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

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

    在我的 data.xml 文件中,我有数据源 bean,就是这样。没有其他 bean,其他所有内容都是自动装配和注释的。

    大概,这个“data.xml”文件就是您在contextConfigLocation context-param 中列出的文件。假设您还将 ContextLoaderListener 添加到您的 web.xml,例如

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

    然后该文件将用于创建第二个 ApplicationContext——根上下文。这就是这个听众所做的。请注意,它实际上是从 all contextConfigLocation 中列出的文件构建上下文,如果您还在该列表中包含了“servlet.xml”,那么您已经加载了两次该配置:here in根上下文以及与 DipatcherServlet 关联的上下文中。希望您现在看到 XML 配置文件和它们配置的 ApplicationContext 之间的明显区别。同一个 XML 文件可以很容易地用于配置两个不同的上下文。这样做是否正确是另一个问题。在这种特殊情况下,它不是。

    我描述这两个上下文的顺序实际上是倒退的。我只是按照你对你所做的事情的描述。作为ServletContextListener 的ContextLoaderListener 将始终在任何servlet 启动之前执行。这意味着首先创建根上下文,然后创建另一个上下文。这是设计使然,当 DispatcherServlet 创建其上下文时,它可以将该上下文添加为根上下文的子上下文。我已经在其他帖子中描述了这种关系。这样做的最重要的影响是根上下文中的 bean 可用于并通过 DispatcherServlet 的上下文。这也适用于自动连接的关系。这很重要,因为 DispatcherServlet only 在其关联的上下文中查找它需要的 bean,例如控制器实例。但是,您的控制器显然必须与支持 bean 连接。因此,传统上,控制器存在于 DispatcherServlet 的上下文中,而支持的 bean 存在于根上下文中。

    然后我尝试将 @Transacational 添加到我的服务 bean 中,但它不会持续存在。

    为了使@Transactional 工作,您必须在注解bean 所在的ApplicationContext 的配置中包含&lt;tx:annotation-driven/&gt; 标签。诀窍是弄清楚“它住在哪里”部分。子项中的 bean 可以覆盖父上下文中的 bean。因此——我只是在这里猜测——如果您将所有 bean 加载到 DispatcherServlet 上下文中,如上所述,但将 &lt;tx:annotation-driven/&gt; 放在根上下文中,您可能在根上下文中有一个正确事务的 bean,但是它不是正在使用的,因为副本“更接近”父/子层次结构中的 servlet,并且它所在的上下文没有获得 &lt;tx:annotation-driven/&gt; 配置。

    当我将 servlet context:component-scan 标签改为指向 com.myapp.web,然后将 context:component-scan 标签添加到 data.xml 文件时,一切正常。

    这仍然在一定程度上取决于您将哪些配置文件包含在哪些 ApplicationContexts 中,但至少我可以说,通过这样做,您从 DispatcherServlet 的上下文中删除了许多导致问题的 bean。特别是,您在根上下文中正确配置的 @Transactional bean 将不再被子上下文中的 bean 遮蔽,并将被注入到您的控制器中,因此您的持久性内容将起作用。

    所以...要带走的主要内容是您有两个相关的 ApplicationContext。您必须始终了解这一事实,并控制哪些 bean 在哪个上下文中运行。

    这涵盖了所有内容吗?

    【讨论】:

    • 非常感谢您的帮助和链接。这些链接提供了我正在寻找的一些说明。不过我确实有一个问题。我的 servlet.xml 中有一个 标记。在我的 data.xml 文件中,我有数据源 bean,就是这样。没有其他 bean,其他所有内容都是自动装配和注释的。然后我尝试将 @Transacational 添加到我的服务 bean 中,但它不会持续存在。当我将 servlet context:component-scan 标签改为指向 com.myapp.web,然后将 context:component-scan 标签添加到 data.xml 文件时,一切正常。
    • 所以我的问题是,你能澄清这是为什么吗?我有一个调度程序 servlet,它查看 servlet.xml,所以这不是根上下文。嗯...我想我还是不完全理解事物是如何组合在一起的。非常感谢。
    • 非常感谢您!我认为您确实帮助清除了我似乎无法从我读过的书籍和 Spring Docs 中看到的东西。我确实将我的 serlvet.xml 文件放入 contextConfigLocation 列表中,正如您所说,这导致了 2 个上下文。这可能不是我唯一的问题,但绝对是其中之一。现在有了你的解释,我应该能够完成并确保一切都配置正确。另外,我感谢您列出 Spring 如何加载文件。我确实认为一切都清楚得多。再次感谢。
    • 这是一个很棒的解释。非常感谢。就我而言,我使用上下文的包含和排除过滤器来控制它并且效果很好!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-19
    相关资源
    最近更新 更多