一尘不染

Spring MVC: Sharing context within ear

spring

我有一个ear包,其中包含一个带普通对象的jar和两个我想使用普通jar的战争Web应用程序。我已将配置设置为通过ContextLoaderListener和Webapp上下文分别为DispatcherServlet使用应用程序范围的上下文。

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

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 Spring MVC应用程序打包为单独的war,并带有如下所示的web.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,例如针对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包既包含战争也包含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

问题是仍然有两个bean实例。每个控制器/ webapp一个,因为每次战争中只有一个Controller。我试图扭曲配置,但是无论我做什么,我要么得到零个实例,要么得到两个实例。

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

我读过许多博客文章,讨论论坛等,他们说这应该就这么简单。有人建议使用JNDI,但据我所知,没有它,应该可以实现。

而且不可能将战争结合在一起并将jar捆在里面。由于它可能适用于此演示应用程序,因此我正在使用的现实生活案例不允许这样做。

在此问题上的任何帮助都将受到高度赞赏。提前致谢。


阅读 347

收藏
2020-04-20

共1个答案

一尘不染

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

据我所知,配置的问题是你正在加载applicationContext.xml加载到中的那个sharedContext,每个webapp也正在加载中,因为它在中提到了context-param contextConfigLocation

由于同一文件被加载两次,因此一次在父上下文中,一次在Web应用程序的根上下文中进行,因此存在副本以及子上下文,即。webapp使用其创建的应用程序,而不使用父级应用程序中创建的应用程序。

更改配置,以免再次加载相同的bean xml两次,它应该可以正常工作。你可以使用parentContextKey并且contextConfigLocation两者都不会加载相同的文件。

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

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

2020-04-20