Sharing an application context between two WARs?

19,822

Solution 1

The general purpose of a web application container like tomcat is that each application is able to run independently (so you can stop and start individual apps without affecting others), which means that there has probably been a lot of effort put into their development specifically to prevent you from doing this. So even if you find a loophole, I would suggest against using it unless it is recommended or at least sanctioned by the designers.

I suggest you start looking for other solutions. For example:

  • Do you really need to share the object instances? If they are stateless you may not need to, and you can simply run a copy of the context in each app.
  • Can you separate the code that you're trying to share into a third WAR that exposes a rest service? Or maybe one of the existing WARs could act as the service.

Solution 2

Our team just had the same requirement--to share Spring beans between multiple WARs in Tomcat, and honestly, answers such as, "Don't do that," are not helpful.

The requirement stems from the fact that we have a multi-WAR application running on Tomcat, and all of the WARs need access to the same RDBMS for persisting information. We are using Spring and Hibernate to access the RDBMs, and all of the WARs share the same schema and ideally can use the same Hibernate SessionFactory and Spring transaction manager.

The answer on how to do it was posted here:

StackOverflow: Sharing ApplicationContext within EAR

and to summarize, you do the following in your web.xml:

<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:yourWarSpecificAppContext.xml</param-value>
</context-param>

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

where beanRefContext.xml contains:

<beans>
  <bean id="sharedContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
    <constructor-arg>
      <list>
        <value>classpath:yourSharedAppContext.xml</value>
      </list>
    </constructor-arg>
  </bean>
</beans>

This uses the Spring ContextSingletonBeanFactoryLocator to expose and share the parent context (in this case using the name "sharedContext"). The shared context will be lazily loaded when the first WAR references it.

Whatever beans you reference in the shared context have to be accessible to all of the WARs, which means that they cannot be loaded from WEB-INF/classes or WEB-INF/lib within a specific WAR. They must be shared, either using an EAR file, or by putting the jars that contain the beans (and dependencies) in the Tomcat shared "lib" folder ($CATALINA_HOME/lib), which is what our team did.

Fair warning that if you use this approach, you are likely to have most of your JARs located in the shared lib folder and not in individual webapps. For our project, this made sense because most of the webapps share and access the same back-end services.

Since the hardcore Tomcat developers are likely to object to putting lots of code into the Tomcat shared lib directory, I'll just enumerate some reasons why the other suggested answers might not work.

  • Using separate application contexts for each WAR would mean having multiple connection pools to the database, one for each WAR, and separate initialization of expensive Hibernate SessionFactory for each WAR, which increases server start time and memory consumption. More generally, it does not allow the state of shared back-end services to be shared across webapps running in the same Tomcat.
  • Putting the persistence code into a separate WAR and using REST calls, at least in our case, is totally inconvenient for developers, and increases the path length to get to the database compared with direct calls to shared beans.

Solution 3

There is an informative blog post I think you should check out: Using a shared parent application context in a multi-war Spring application

Solution 4

There is maybe a way if you start an embedded jetty server and access both web apps from the class where you start and configure the jetty server.

See:

Embedding Jetty

Share:
19,822

Related videos on Youtube

Stefan Kendall
Author by

Stefan Kendall

Updated on October 28, 2020

Comments

  • Stefan Kendall
    Stefan Kendall about 3 years

    Is there a way to share an app-context between two deployed wars? One war needs to wire-in the services of another, and I don't know where to start with this.

    • Joel
      Joel over 12 years
      Could you not pass your context using SOAP and two Web Service implementations?
  • Amol Katdare
    Amol Katdare over 12 years
    +1 for suggesting against what smells like a flawed design. I would also recommend the use of some very light weight service enabler like Hessian/Burlap hessian.caucho.com/doc to expose and consume services between these web apps
  • Pat
    Pat almost 7 years
    There are 2 parts to the question: Is there a way to share an app-context between two deployed wars and to wire services in another war. The first part is a genuine design, breaking one big system into smaller webapplications, sharing the same context root. This enabled shorter release cycles by allowing testing of changed modules in isolation, without requiring longer regression test cycles. I do not believe it is a flawed design. The second part, not so... I would recommend not going there.
  • Aniket Sahrawat
    Aniket Sahrawat over 3 years
    I would have simply copied everything over to another application and run them independent of each other lmao.

Related