2013-04-23 62 views
12

我有一个耳朵包装,其中包含一个具有常用对象的jar和两个我想使用常用jar的war webapps。我已经为DispatcherServlet分别设置了通过ContextLoaderListener和webapp上下文使用应用程序范围上下文的配置。Spring MVC:在耳朵内共享上下文

我的演示应用程序的设置大致以下

  • 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

<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> 
  • webapp1webapp2被打包成独立的战争与W¯¯Spring MVC应用eb.xml文件像下面

    <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> 
    

XX-servlet.xml中像Web应用程序特定的上下文。 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> 
  • 共享bean被@Autowired在正常的方式在控制器类

    @Autowired 
    MySharedBean mySharedBean 
    
  • 耳包包括战争和罐子,结构是这样

    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实例。每个控制器/ Web应用程序一个,因为每场战争中只有一个控制器。我尝试过使用配置,但无论我做什么,我都会获得零个实例或两个实例。

我从内存转储中检查了Eclipse MAT的引用,实际上有4个实例,但我猜这两个是用于Spring内部使用的。无论如何,从那里可以清楚地看到每个控制器都有自己的实例。

我读过大量的博客文章,论坛等,他们说这应该是这样简单。有人建议JNDI,但据我了解,如果没有它,这应该是可能的。

这是不可能的,结合战争和捆绑罐里面。因为它可能适用于这个演示应用程序,我正在使用的真实案例不允许这样做。

任何有关这个问题的帮助是非常感谢。提前致谢。

SpringSource example from 2007对于Spring 2.X,它具有相同但具有不同配置的功能。有点过时了,正在寻找一个基于Spring 3.X的解决方案,就像赏金描述中的那样。

回答

3

我解决了它。

问题出现在课堂加载中,因为我在@ Akshay的回答中对此有所怀疑。

Maven在每个war包中都包含了spring libs,所以它们被加载了多次。要解决这个问题,需要generate skinny wars

我假设Akshay关于从web.xml中的context-params中删除contextConfigLocation的回答的注释也起着关键作用。

7

就应用程序上下文层次结构而言,我不相信从Spring 2.x到3.x有任何变化。

从我可以告诉,你的配置的问题是,你正在加载applicationContext.xml - 一个加载到sharedContext,也是由每个webapp加载,因为其中提到的事实context-paramcontextConfigLocation。由于相同的文件被加载两次,一次在父上下文中,一次在Web应用程序的根上下文中,有副本和子上下文(即上下文)。 webapp使用它创建的那些,而不是父类中存在的那些。

更改你的配置,所以你不重新加载相同的bean xml两次,它应该工作正常。您可以使用parentContextKeycontextConfigLocation都只是不加载相同的文件。

更新: 除上述之外,还需要检查共享jar是否对战争可见(在允许共享相同实例时可见)。我试图从博客中运行示例,当我将它作为Java EE6应用程序部署时,它并不适用于我,这是因为战争内部耳瓶可见性规则已从Java EE5更改为EE6。当我在玻璃鱼的兼容模式下运行样品时,一切都按预期工作。

因此,请检查您的EAR/WARs以查看您正在运行的servlet规范,并确保您的服务器正在相应地部署应用程序。

如果您必须升级到Java EE 6,请确保您遵循最新的可见性规则http://docs.oracle.com/cd/E19226-01/820-7688/gjjdt/index.html。检查战争的MANIFEST文件以确保它们具有Class-Path配置中明确提及的所有耳瓶。

希望这会有所帮助。

+0

感谢您的回复@Akshay。如果我理解正确,你的建议是从'web上去掉'contextConfigLocation'。xml'文件。我试了一下,结果是IOException。根据日志,'ContextLoaderListener'尝试从/ WEB-INF /加载applicationContext.xml。我认为这是我将位置作为上下文参数添加到第一位的原因。 – kaskelotti 2013-04-26 04:01:09

+0

[此博客文章](http://internna.blogspot.fr/2007/05/sharing-global-spring-application.html)有效地建议在/ WEB-INF /中添加一个空的applicationContext.xml。那么,我这样做了,应用程序启动了,但日志显示我仍然有两个共享bean实例。实际上,'sharedContext'似乎创建了两次。 – kaskelotti 2013-04-26 04:26:27

+0

你可以尝试没有contextconfiglocation和lovcator工厂选择器作为cobtext params? – Akshay 2013-04-26 05:18:48

2

我们有类似的问题。查看我们为实验创建的这个简单的maven示例(带有2个WEB模块的EAR和一个通过父级弹簧上下文服务模块共享): EAR with shared spring context between wars