java Spring MVC:在耳内共享上下文
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16162877/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring MVC: Sharing context within ear
提问by kaskelotti
I have an ear package that contains one jar with common objects and two war webapps that I'd like to use the common jar. I've setup the configuration to use application wide context via ContextLoaderListener and webapp contexts separately for DispatcherServlet.
我有一个 ear 包,其中包含一个带有普通对象的 jar 和两个我想使用普通 jar 的 war webapp。我已经将配置设置为通过 ContextLoaderListener 和 webapp 上下文分别为 DispatcherServlet 使用应用程序范围的上下文。
The setup of my demo app is roughly the following
我的演示应用程序的设置大致如下
common.jar
contains applicationContext.xmland beanRefContext.xml, which are supposed to be application (ear) wide context. The files are like below. sharednamespace is where the shared bean is located.
common.jar
包含applicationContext.xml和beanRefContext.xml,它们应该是应用程序(耳朵)范围的上下文。文件如下。共享命名空间是共享 bean 所在的位置。
applicationContext
应用上下文
<beans>
<!-- namespace etc declarations omitted -->
<context:annotation-config />
<context:component-scan base-package="study.spring.multicontext.shared" />
</beans>
beanRefContext.xml
beanRefContext.xml
<beans>
<!-- namespace etc declarations omitted -->
<bean id="sharedContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>classpath*:applicationContext.xml</value>
</list>
</constructor-arg>
</bean>
</beans>
webapp1
andwebapp2
are Spring MVC applications packaged as separate wars with web.xmlfile like below<web-app> <context-param> <param-name>parentContextKey</param-name> <param-value>sharedContext</param-value> </context-param> <context-param> <param-name>locatorFactorySelector</param-name> <param-value>classpath:beanRefContext.xml</param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>dos</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/dos-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dos</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
webapp1
并且webapp2
是 Spring MVC 应用程序与web.xml文件打包为单独的War,如下所示<web-app> <context-param> <param-name>parentContextKey</param-name> <param-value>sharedContext</param-value> </context-param> <context-param> <param-name>locatorFactorySelector</param-name> <param-value>classpath:beanRefContext.xml</param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>dos</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/dos-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dos</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
and xx-servlet.xmllike for webapp specific context. webnamespace is where the controllers are located.
和xx-servlet.xml类似用于 webapp 特定上下文。web命名空间是控制器所在的位置。
<beans>
<!-- namespace etc declarations omitted -->
<context:component-scan base-package="study.spring.multicontext.web"/>
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="suffix" value=".jsp"/>
</bean>
</beans>
The shared bean is @Autowired in normal fashion in Controller classes
@Autowired MySharedBean mySharedBean
ear package contains both wars and jar, and structure is like
ear | |--common.jar | |--META-INF | |--applicationContext.xml | |--beanRefContext.xml | |--webapp1.war | |--WEB-INF | |--xx-servlet.xml | |--web.xml | |--webapp2.war | |--WEB-INF | |--xx-servlet.xml | |--web.xml
共享 bean 在控制器类中以正常方式@Autowired
@Autowired MySharedBean mySharedBean
耳朵包包含wars和jar,结构就像
ear | |--common.jar | |--META-INF | |--applicationContext.xml | |--beanRefContext.xml | |--webapp1.war | |--WEB-INF | |--xx-servlet.xml | |--web.xml | |--webapp2.war | |--WEB-INF | |--xx-servlet.xml | |--web.xml
The problem is that there will still be two instances of the bean. One for each controller/webapp, since there's only one Controller in each of the wars. I have tried to twiddle with the configuration, but no matter what I do, I either get zero instances or two instances.
问题是仍然会有两个 bean 实例。每个控制器/webapp 一个,因为在每一场War中只有一个控制器。我试图摆弄配置,但无论我做什么,我要么得到零个实例,要么得到两个实例。
I checked the references with Eclipse MAT from a memory dump, and there are actually 4 instances, but I guess the two are for Spring internal use. Anyway, from there it's clearly visible that each controller has it's own instance.
我从内存转储中检查了 Eclipse MAT 的引用,实际上有 4 个实例,但我猜这两个是供 Spring 内部使用的。无论如何,从那里可以清楚地看到每个控制器都有自己的实例。
I've read numerous of blog posts, discussion forums, etc where they say that this should be as simple as this. Some suggest JNDI, but as I've understood, this should be possible without it.
我读过许多博客文章、论坛等,他们说这应该像这样简单。有人建议使用 JNDI,但据我所知,没有它应该是可能的。
And it's not possible to combine the wars and bundle the jar inside. As it might work for this demo app, the real life case I'm working with does not allow this.
并且不可能将War结合起来并将罐子捆绑在里面。由于它可能适用于这个演示应用程序,我正在处理的现实案例不允许这样做。
Any help on this matter is highly appreciated. Thanks in advance.
对此事的任何帮助表示高度赞赏。提前致谢。
SpringSource example from 2007for Spring 2.X that does the same but with different configuration. A bit outdated and looking for a Spring 3.X based solution, as dscribed in the bounty description.
2007 年用于 Spring 2.X 的SpringSource 示例,其功能相同但配置不同。有点过时,正在寻找基于 Spring 3.X 的解决方案,如赏金描述中所述。
采纳答案by kaskelotti
I got it solved.
我解决了。
The problem was in class loading as I suspected in comments to @Akshay's answer.
正如我在对@Akshay 的回答的评论中所怀疑的那样,问题出在课堂加载中。
Maven included spring libs inside each war package, so they were loaded multiple times. To fix this, one needs to generate skinny wars.
Maven 在每个 war 包中都包含了 spring 库,因此它们被多次加载。为了解决这个问题,需要产生瘦身War。
I assume Akshay's note on his answer to remove the contextConfigLocation
from context-params in web.xml was in key role as well.
我认为 Akshay 关于他contextConfigLocation
在 web.xml 中删除from context-params 的回答的注释也起到了关键作用。
回答by Akshay
I do not believe anything has changed from Spring 2.x to 3.x as far as application context hierarchies are concerned.
就应用程序上下文层次结构而言,我认为从 Spring 2.x 到 3.x 没有任何变化。
From what I can tell, the issue with your config is that you are are loading the applicationContext.xml
- the one which is loaded into the sharedContext
, is also being loaded by each webapp, because of the fact that its mentioned in the context-param
contextConfigLocation
.
从我可以告诉你配置的问题是,你正在加载的applicationContext.xml
-这被装入一个sharedContext
,也正在每个web应用程序加载,因为它在提到这样一个事实context-param
contextConfigLocation
。
Since the same file is loaded twice, once in the parent context and once in the web application's root context, there are copies made, and the child context, ie. webapp, uses the ones it created, not the ones that are present in the parent.
由于同一个文件被加载两次,一次在父上下文中,一次在 Web 应用程序的根上下文中,因此会创建副本,以及子上下文,即。webapp,使用它创建的那些,而不是存在于父级中的那些。
Change your config so you don't reload the same beans xml twice, and it should work fine. You can use parentContextKey
and contextConfigLocation
both just don't load the same files.
更改您的配置,这样您就不会两次重新加载相同的 beans xml,它应该可以正常工作。您可以使用parentContextKey
并且contextConfigLocation
两者都不要加载相同的文件。
Update: In addition to the above, you also need to check if the shared jar is visible to the wars (visible as in allowed to share the same instance.). I tried to run the sample from the blog and it did not work for me when I deployed it as a Java EE6 application, and that's because the rules for ear jar visibility inside wars changed from Java EE5 to EE6. When I run the sample in compatibility mode of Glass Fish, everything works as expected.
更新:除上述之外,您还需要检查共享 jar 是否对War可见(可见,允许共享同一实例。)。我尝试运行博客中的示例,但当我将其部署为 Java EE6 应用程序时,它对我不起作用,这是因为War中的耳罐可见性规则从 Java EE5 更改为 EE6。当我在 Glass Fish 的兼容模式下运行示例时,一切都按预期进行。
So check your EAR / WARs to see what servlet spec you are running, and make sure your server is deploying the application accordingly.
因此,请检查您的 EAR / WAR 以查看您正在运行的 servlet 规范,并确保您的服务器正在相应地部署应用程序。
If you have to upgrade to Java EE 6, make sure you are following the latest visibility rules http://docs.oracle.com/cd/E19226-01/820-7688/gjjdt/index.html. Check the MANIFEST
files of the wars to ensure they have all ear jars explicitly mentioned in the Class-Path
configuration.
如果您必须升级到 Java EE 6,请确保您遵循最新的可见性规则http://docs.oracle.com/cd/E19226-01/820-7688/gjjdt/index.html。检查MANIFEST
wars的文件以确保它们在Class-Path
配置中明确提到了所有的耳罩。
Hope this helps.
希望这可以帮助。
回答by Balaban Mario
We had a similar problem. Check this simple maven example (EAR with 2 WEB modules and a shared via parent spring context service module ) we have created for the experiment: EAR with shared spring context between wars
我们遇到了类似的问题。检查我们为实验创建的这个简单的 maven 示例(EAR with 2 WEB modules and a shared via parent spring context service module ): EAR with shared spring context between wars
回答by Sandesh
Though this question is old one, if someone is wondering why the documented approachis not working in Spring Framework 5.0+. The support for sharing context within ear is currently broken in Spring Framework 5.0+ as of posting of this answer. There is an existing issue open on Spring Framework Issue-20805
虽然这个问题很老,但如果有人想知道为什么记录的方法在 Spring Framework 5.0+ 中不起作用。在发布此答案时,Spring Framework 5.0+ 中目前已破坏了对在耳内共享上下文的支持。Spring Framework Issue-20805上存在一个未解决的现有问题