Spring XML 文件配置层次帮助/说明 [英] Spring XML file configuration hierarchy help/explanation

查看:29
本文介绍了Spring XML 文件配置层次帮助/说明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我第一次开始学习 Spring 时,是在 applicationContext.xml 文件中配置的.然后,当我开始专门阅读有关 Spring 最新版本的书籍时,他们都在单独的 XML 文件中完成了配置,例如 myapp-servlet-xml、myapp-security.xml、myapp-service.xml 等,通过在 web.xml 文件中配置 contextConfigLocation.因此,例如,我一直在关注的代码有这个,因为它是 contextConfigLocation:

When I first started learning about Spring, things were configured in the applicationContext.xml file. Then as I started to read books specifically on more recent versions of spring, they've all done the configuration in separate XML files such as myapp-servlet-xml, myapp-security.xml, myapp-service.xml, etc., by configuring a contextConfigLocation in the web.xml file. So, for instance, the code I've been following along with had this as it's 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 中.

Anyway, recently I ran into a configuration issue (which the helpful people here at StackOverflow helped me figure out) that was due to this separation. There was no applicationContext.xml file for the examples from these books and later on when I tried adding automatic scanning and annotations to the app this caused issues. I tried moving everything into applicationContext.xml and doing away with the other files and that solved the problem. Nothing else changed, I just put everything in applicationContext.xml.

因此,这与其他人的评论一起使我明白,即使您不创建 applicationContext.xml,它仍在使用中,并且它是某种配置层次结构的顶级.我希望其他人可以向我解释这一切是如何运作的,因为我在任何地方都没有遇到过任何解释.

So, this, along with comments from others, has lead to me sort of understand that even if you don't create an applicationContext.xml, it's still being used and it is the top level of some sort of configuration hierarchy. I'm hoping someone else can explain to me how this all works because I've not come across any explanation on it anywhere.

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

So for example, if I put certain context:component-scan tags into configuration files that are below applicationContext.xml, it could cause certain classes to not get scanned. Things of that nature. I don't understand the precedence and what has to go where to be sure it's seen application wide and so on. If anyone can clearly explain it or point me to a resource that explains it I would much appreciate it, thank you. Hopefully what I'm asking makes sense.

推荐答案

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

There's nothing special about the file named "applicationContext.xml" except that it's the name Spring tends to expect as its default configuration file. Using one file named that or multiple files named "dog.xml", "cat.xml", and "alien.xml" will work exactly the same way. The trouble you're having comes from having multiple ApplicationContexts in use at the same time, not from having multiple XML files. I've recently answered a couple of questions from people who had problems caused by not understanding these concepts. Check out those answers, and see what questions you still have:

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

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

针对您的新问题:

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

I had a <context:component-scan base-package="com.myapp"/> tag in my servlet.xml.

我猜这个servlet.xml"文件的名字类似于foo-servlet.xml,其中你的web.xml中配置的DispatcherServlet被命名为foo",比如

I'm guessing this "servlet.xml" file is named like foo-servlet.xml, where the DispatcherServlet configured in your web.xml is named "foo", like

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

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

By convention, when this DispatcherServlet starts, it'll create a new ApplicationContext that's configured by the file foo-servlet.xml, derived from the servlet-name. Now, since you put a context:component-scan in there, it's going to recursively scan the given package and create beans for all annotated classes. The package you gave it, com.myapp, looks like it's the base package for your entire app, so Spring will create beans from all of the annotated classes in your app, including the data access ones, in this one ApplicationContext that's associated to the DispatcherServlet. Typically, this context should only have view-layer stuff and beans that directly support the DispatcherServlet in it, so this was something of a misconfiguration.

在我的 data.xml 文件中,我有数据源 bean,仅此而已.没有其他 bean,其他所有内容都是自动装配和注释的.

In my data.xml file I had data source beans and that was it. No other beans, everything else was autowired and annotated.

据推测,这个data.xml"文件就是您在 contextConfigLocation 上下文参数中列出的文件.假设您还将 ContextLoaderListener 添加到您的 web.xml 中,例如

Presumably, this "data.xml" file is the one you listed in the contextConfigLocation context-param. Assuming you'd also added the ContextLoaderListener to your web.xml, like

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

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

then that file will be used to create a second ApplicationContext--the root context. That's what this listener does. Note that it actually builds the context from all the files listed in contextConfigLocation, and if you also included your "servlet.xml" in that list, then you've loaded that config twice: here in the root context as well as in the context associated with the DipatcherServlet. Hopefully you see now how there's a distinct division between the XML configuration files and the ApplicationContexts that they configure. The same XML file can easily be used to configure two different contexts. Whether doing so is correct or not is another question. In this particular case, it isn't.

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

The order I've described these two contexts in is actually backwards. I was just following your description of what you did. The ContextLoaderListener, being a ServletContextListener, will always execute before any servlet starts up. This means the root context is created first, and the other context second. This is by design so that when the DispatcherServlet creates its context, it can add that context as a child of the root context. I've described this relationship in those other posts. The most important effect of this is that beans in the root context are available to and via the DispatcherServlet's context. That applies to autowired relationships, too. That's important because the DispatcherServlet only looks in its associated context for beans that it needs, like controller instances. Your controllers, though, obviously have to be wired with supporting beans. Thus, traditionally, the controllers live in the DispatcherServlet's context, and the supporting beans live in the root context.

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

I then tried to add @Transacational to my service bean and it wouldn't persist.

为了让@Transactional 工作,您必须在注释 bean 所在的 ApplicationContext 的配置中包含 <tx:annotation-driven/> 标记.诀窍是弄清楚它住在哪里"部分.子级中的 Bean 可以覆盖父级上下文中的 Bean.因此——我只是在这里猜测——如果你像我上面描述的那样将所有 bean 加载到 DispatcherServlet 上下文中,但将 <tx:annotation-driven/> 放在根上下文中,您可能在根上下文中有一个正确事务性的 bean,但它不是正在使用的 bean,因为副本更接近"父/子层次结构中的 servlet,并且它所在的上下文没有得到 配置.

In order for @Transactional to work, you must include the <tx:annotation-driven/> tag in the configuration of the ApplicationContext where the annotated bean lives. The trick is figuring out the "where it lives" part. Beans in a child can override beans in a parent context. Therefore--I'm just guessing here--if you loaded all your beans into the DispatcherServlet context as I described above but put the <tx:annotation-driven/> in the root context, you might have a bean in the root context that's correctly transactional, but it's not the one being used because the duplicate is "closer" to the servlet in the parent/child hierarchy, and the context it's in didn't get a <tx:annotation-driven/> configuration.

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

When I changed the servlet context:component-scan tag to instead point at com.myapp.web and then added a context:component-scan tag to the data.xml file, everything worked.

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

It still depends somewhat on exactly which config files you were including in which ApplicationContexts, but at the very least I can say that by doing this, you removed a lot of beans from the DispatcherServlet's context which were causing problems. In particular, your correctly-configured @Transactional beans in the root context would no longer be shadowed by beans in the child context and would be injected into your controllers, so your persistence stuff would work then.

所以...要带走的主要内容是您有两个相关的 ApplicationContext.您必须始终意识到这一事实,并控制哪些 bean 出现在哪个上下文中.

So... the main thing to take away is that you have two related ApplicationContexts. You have to remain aware of that fact and stay in control of which beans go in which context.

这是否涵盖所有内容?

这篇关于Spring XML 文件配置层次帮助/说明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆