春季MVC:在耳朵内共享上下文

2022-09-04 20:56:03

我有一个耳朵包装,其中包含一个带有常见对象的罐子和两个我想使用通用罐子的战争Web应用程序。我已经将配置设置为通过 ContextLoaderListener 和 Webapp context 分别用于 DispatcherServlet 使用应用程序范围的上下文。

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

  • common.jar包含 applicationContext.xmlbeanRefContext.xml,它们应该是应用程序(耳朵)范围的上下文。文件如下所示。共享命名空间是共享 Bean 所在的位置。

应用语境

<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>
  • webapp1并且是Spring MVC应用程序打包为与Web.xml文件的独立战争,如下所示webapp2

    <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就像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>
  • 共享的 Bean 在 Controller 类中以正常方式@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 示例来自 2007 年的 Spring 2.X,它执行相同的操作,但配置不同。有点过时,正在寻找基于Spring 3.X的解决方案,如赏金描述中所述。


答案 1

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

据我所知,您的配置的问题在于您正在加载 - 加载到 中的那个也由每个webapp加载,因为它在.applicationContext.xmlsharedContextcontext-paramcontextConfigLocation

由于同一文件加载两次,一次在父上下文中,一次在Web应用程序的根上下文中,因此可以创建副本和子上下文,即。webapp 使用它创建的那些,而不是存在于父级中的那些。

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

更新:除了上述之外,您还需要检查共享jar对战争是否可见(可见,如允许共享同一实例)。我试图从博客中运行这个示例,当我将其部署为Java EE6应用程序时,它对我不起作用,这是因为战争中耳罩可见性的规则从Java EE5更改为EE6。当我在Glass Fish的兼容模式下运行示例时,一切都按预期工作。

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

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

希望这有帮助。


答案 2

我解决了它。

问题在于类加载,正如我在评论中@Akshay的答案所怀疑的那样。

Maven 在每个战争包中都包含弹簧库,因此它们被加载了多次。为了解决这个问题,人们需要产生瘦弱的战争

我假设Akshay关于他的答案的注释,即从web.xml中删除上下文参数也起着关键作用。contextConfigLocation


推荐