2 Replies Latest reply on Sep 14, 2011 5:03 AM by billhong

    How to share Spring application context across multiple WARs in AS7

    billhong

      Our company has been working on migrate our web product from Weblogic to JBoss. We have ported our product successfully to AS6 a couple of weeks before. However, we got problems and failed to migrate it to AS7.

       

      Here is the problem we got:

      Our web product is EAR application with multiple WARs. Currently, it initializes a Spring context when EAR package is deploying prior to loading other WARs. This Spring context will be shared for all WARs within this EAR application. In weblogic we define "ApplicationLifecycleListener" to initialize Spring context. In JBoss AS6 we worked out a solution that put a SAR in EAR and let MBean service do same job like "ApplicationLifecycleListener". The package would look like:

      abc.ear

              test1.war

              test2.war

              SpringContextLoader.sar

      However, this won't work in AS7. We run into two problems actually:

      1) It seems MBean service won't execute prior to loading other WARS. In AS6 it always executes first when deploy the EAR application.

      2) The Spring context loaded by SAR won't be accessible by WAR packages. I'm wondering if that is because class loader isolation in EAR package.

       

      Is there a way to prevent class loader isolation across WARs and let them use same class loader within EAR? Would anyone kindly provide any suggestions to migrate this solution to AS7?

       

       

      Thanks!

        • 1. Re: How to share Spring application context across multiple WARs in AS7
          swoeste

          Hi Bill,

          we have nearly the same problem here. Actually I am trying to port our application from AS4 (also successfully running with AS5) to AS7.

           

          The behavior is nearly the same as you already described. Our Spring Context is initialized during the deployment and will be shared with all WARs within this EAR application.

           

          Our Structure:

               Application.ear

          |-X.war

          |-Y.war

          |-EJB.jar

           

          The deployment finish successfully but if I try to access the registered web context, then I get the following exception:

          java.lang.IllegalStateException: Context attribute is not of type WebApplicationContext: Root WebApplicationContext: startup date [Wed Sep 14 08:43:22 CEST 2011]; parent: ApplicationContext 'four-tier'

                  org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext(WebApplicationContextUtils.java:124)

          org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext(WebApplicationContextUtils.java:99)
          de.zeb.control.fw.pl.presentationutils.filter.InitializingSpringContextFilter.doFilterInternal(InitializingSpringContextFilter.java:45)

          org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
          org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:83)

          org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
          de.zeb.control.fw.pl.presentationutils.filter.IE6Kb843518Filter.doFilter(IE6Kb843518Filter.java:76)

          org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)

          org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

          de.zeb.control.fw.pl.presentationutils.filter.GZIPCompressionFilter.doFilter(GZIPCompressionFilter.java:66)

           

          The Code that throws the exception is the following:

            public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {

                      Assert.notNull(sc, "ServletContext must not be null");

                      Object attr = sc.getAttribute(attrName);

                      if (attr == null) {

                            return null;

                      }

                      if (attr instanceof RuntimeException) {

                            throw (RuntimeException) attr;

                      }

                      if (attr instanceof Error) {

                            throw (Error) attr;

                      }

                      if (attr instanceof Exception) {

                            throw new IllegalStateException((Exception) attr);

                      }

                      if (!(attr instanceof WebApplicationContext)) {

                            throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr);

                      }

                      return (WebApplicationContext) attr;

                }

           

          While I was debugging that code I have discovered that attr is a XMLWebApplicationContext which implements the WebApplicationContext interface. So it seems that there is a problem with the classloader …

           

          Have you already solved your problem or does any one has a solution for this kind of problem?

           

          Thanks

          Sebastian

          • 2. Re: How to share Spring application context across multiple WARs in AS7
            billhong

            Sebastian,

             

            The class loader would be fine as long as all shared JAR packages are put in /lib folder of the EAR package. The trick here is AS7.0 loads WARs, SARs in the same EAR package by multiple threads. You won't know which component will be initialized first when doing deployment. Therefore, I gave up the way to load Spring Context in mbean service since there's no way to guarantee SAR is loaded first.

             

            Here is the way I solve this problem in my environment:

            1) Create a listener which is used to load spring context and put it in web.xml for all WARs.

                <listener>
                    <listener-class>com.xxx.SpringContextLoader</listener-class>
                </listener>

            2) Create synchronized method and only allows the first thread call this method to load spring context. Other threads will need to wait until Spring Context is loaded.

             

            I still do not find a similar way in JBoss which acts like Weblogic's ApplicationLifecycleListener. Please let me know if you work out a better solution.

             

             

             

            -Bill