Announcement Announcement Module
Collapse
No announcement yet.
How to configure Spring in both EJB and WAR when deploying in an EAR? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to configure Spring in both EJB and WAR when deploying in an EAR?

    Asked this on the springframework-user mailing list but got no replies, so I'm trying my luck here.

    I'm trying to use Spring 2.5.1 in an EAR on both the EJB3 side and the Web app (WAR) side (built using Maven 2, deployed on Glassfish v2).

    The entire project structure follows that of the Maven 2 simple J2EE archetype, with a root project that defines sub-projects "abc-ear" depends on "abc-web" depends on "abc-ejb".

    On the EJB3 side, I'm using the SpringBeanAutowiringInterceptor to inject my dependencies into my (annotated) EJBs. I have a "beanRefContext.xml" that merely creates a ClassPathXmlApplicationContext which contains the actual bean wirings.

    On the WAR side, I'm using Spring + Spring MVC, so the DispatcherServlet picks up the Spring configuration from "WEB-INF/abc-servlet.xml".

    I have no problems when building and deploying each layer individually, whether from the command-line (Maven2) or my IDE (Eclipse 3.3). As an aside, I had to place the Spring framework JAR in the container's "lib" directory so the EJB JARs (which don't support packaging dependent JARs) can find and use it. This meant that my WAR (and my EAR) don't have a separate copy of the Spring JARs.

    However, when the EAR project is built, and I try to deploy the EAR artifact, I run into an exception when my EJB is being instantiated. Here's a snippet of the exception trace:
    Code:
    [#|2008-02-22T15:22:03.621+0800|INFO|sun-appserver9.1|javax.enterprise.system.container.ejb|_ThreadID=21;_ThreadName=httpSSLWorkerThread-8080-0;|EJB5070:
    Exception creating stateless session bean : [{0}]
    org.springframework.beans.factory.access.BootstrapException: Unable to
    return specified BeanFactory instance: factory key [null], from group
    with resource name [classpath*:beanRefContext.xml]; nested exception
    is org.springframework.beans.factory.NoSuchBeanDefinitionException: No
    unique bean of type [org.springframework.beans.factory.BeanFactory] is
    defined: expected single bean but found 2
           at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:410)
           at org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.getBeanFactoryReference(SpringBeanAutowiringInterceptor.java:132)
           at org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.getBeanFactory(SpringBeanAutowiringInterceptor.java:113)
           at org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.autowireBean(SpringBeanAutowiringInterceptor.java:93)
           ...
    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
    No unique bean of type [org.springframework.beans.factory.BeanFactory]
    is defined: expected single bean but found 2
           at org.springframework.beans.factory.BeanFactoryUtils.beanOfType(BeanFactoryUtils.java:379)
           at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:400)
           ... 68 more
    |#]
    I figure that basically Spring is finding two separate objects that implement the BeanFactory interface when both the EJB JAR and the WAR are deployed in a single EAR.

    All the above seems like a common scenario, so I'm wondering if anyone else has successfully done what I'm trying to accomplish? Basically, how do I configure Spring in both my EJB and WAR layer so they deploy nicely when in an EAR?

  • #2
    Hi,
    Are you be able to figure out how to resolve this issue

    thanks,
    muazzam Khan

    Originally posted by alistair View Post
    Asked this on the springframework-user mailing list but got no replies, so I'm trying my luck here.

    I'm trying to use Spring 2.5.1 in an EAR on both the EJB3 side and the Web app (WAR) side (built using Maven 2, deployed on Glassfish v2).

    The entire project structure follows that of the Maven 2 simple J2EE archetype, with a root project that defines sub-projects "abc-ear" depends on "abc-web" depends on "abc-ejb".

    On the EJB3 side, I'm using the SpringBeanAutowiringInterceptor to inject my dependencies into my (annotated) EJBs. I have a "beanRefContext.xml" that merely creates a ClassPathXmlApplicationContext which contains the actual bean wirings.

    On the WAR side, I'm using Spring + Spring MVC, so the DispatcherServlet picks up the Spring configuration from "WEB-INF/abc-servlet.xml".

    I have no problems when building and deploying each layer individually, whether from the command-line (Maven2) or my IDE (Eclipse 3.3). As an aside, I had to place the Spring framework JAR in the container's "lib" directory so the EJB JARs (which don't support packaging dependent JARs) can find and use it. This meant that my WAR (and my EAR) don't have a separate copy of the Spring JARs.

    However, when the EAR project is built, and I try to deploy the EAR artifact, I run into an exception when my EJB is being instantiated. Here's a snippet of the exception trace:
    Code:
    [#|2008-02-22T15:22:03.621+0800|INFO|sun-appserver9.1|javax.enterprise.system.container.ejb|_ThreadID=21;_ThreadName=httpSSLWorkerThread-8080-0;|EJB5070:
    Exception creating stateless session bean : [{0}]
    org.springframework.beans.factory.access.BootstrapException: Unable to
    return specified BeanFactory instance: factory key [null], from group
    with resource name [classpath*:beanRefContext.xml]; nested exception
    is org.springframework.beans.factory.NoSuchBeanDefinitionException: No
    unique bean of type [org.springframework.beans.factory.BeanFactory] is
    defined: expected single bean but found 2
           at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:410)
           at org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.getBeanFactoryReference(SpringBeanAutowiringInterceptor.java:132)
           at org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.getBeanFactory(SpringBeanAutowiringInterceptor.java:113)
           at org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.autowireBean(SpringBeanAutowiringInterceptor.java:93)
           ...
    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
    No unique bean of type [org.springframework.beans.factory.BeanFactory]
    is defined: expected single bean but found 2
           at org.springframework.beans.factory.BeanFactoryUtils.beanOfType(BeanFactoryUtils.java:379)
           at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:400)
           ... 68 more
    |#]
    I figure that basically Spring is finding two separate objects that implement the BeanFactory interface when both the EJB JAR and the WAR are deployed in a single EAR.

    All the above seems like a common scenario, so I'm wondering if anyone else has successfully done what I'm trying to accomplish? Basically, how do I configure Spring in both my EJB and WAR layer so they deploy nicely when in an EAR?

    Comment


    • #3
      It could be that the WAR is being deployed before the EAR and loads a separate Spring container (bean factory). When the EJB gets loaded it expects somehow to resolve only 1 spring container but finds 2 because the SpringAutowireInterceptor created a 2nd spring container on first execution.

      Would that make any sense ?

      I don't know the solution for you but I think you should look into executing the spring container bootstrap code only once. If you can get the EJB layer to create your spring container with all config maybe then you can get the web layer to use that spring container instead of creating its own.

      I'm sure someone that been through this before has a readymade solution.

      Comment


      • #4
        Configure Spring

        Do you have 2 xml files that load the same spring beans ?
        1. referred by beanRefFactory.xml
        2. referred by WEB-INF/abc-servlet.xml

        Comment


        • #5
          Some useful XML snippets

          I have a working EAR-based app that loads two app contexts:

          1. The business layer context; contains all domain services (SLSBs, transactional POJOs), the datasource, the PlatformTransactionManager, etc.

          2. The web layer context: contains all the web controllers, view builders, etc.; is a child of the first context, so it inherits all the service beans, etc.

          Here's the relevant bit of my web.xml:

          Code:
            <context-param>
              <param-name>contextConfigLocation</param-name>
                  <!-- Can specify multiple config files here separated by commas, semi-colon or whitespace -->
              <param-value>/WEB-INF/web-tier-beans.xml</param-value>
            </context-param>
          
            <!-- Load a parent ApplicationContext containing the service layer beans -->
            <context-param>
              <param-name>locatorFactorySelector</param-name>
              <!-- This file is in the root of the EJB JAR file -->
              <param-value>beanRefContext.xml</param-value>
            </context-param>
            <context-param>
              <param-name>parentContextKey</param-name>
              <!-- This is a bean name in the above XML file -->
              <param-value>serviceBeanFactory</param-value>
            </context-param>
            
            <!-- SpringSource recommends a listener over a servlet for loading the context -->
              <listener>
                  <listener-class>
                      org.springframework.web.context.ContextLoaderListener
                  </listener-class>
              </listener>
          My beanRefContext.xml contains one bean:
          Code:
          <!-- The purpose of this XML file is to tell ContextSingletonBeanFactoryLocator how to create the shared ApplicationContext that's accessible to any EJBs extending AbstractStatelessSessionBean.
            -->
          <bean id="serviceBeanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
            <constructor-arg>
              <list>
                <!-- POJOs -->
                <value>business-layer-pojos.xml</value>
                <!-- JNDI stuff -->
                <value>datasource-bean.xml</value>
                <value>entity-home-beans.xml</value>
                <value>misc-jndi-beans.xml</value>
                <value>session-beans.xml</value>
              </list>
            </constructor-arg>
          </bean>
          I'm pretty sure I worked all this out by reading the Reference Guide, so make sure you check it out.

          Comment


          • #6
            maybe a classloader problem?

            I'm facing the same issue with a configuration that is very similar to the Andrews one.
            I have a maven2 ear project made of an ejb project and a war project which is deployed on glassfish v2.
            I'm using spring 2.5.5 and i'm trying to initialize the ejb appContext through the web application.

            Here is my web.xml:

            Code:
            <display-name>Archetype Created Web Application</display-name>
                <context-param>
                    <param-name>contextConfigLocation</param-name>
                    <param-value>WEB-INF/applicationContext.xml</param-value>
                </context-param>
                <context-param>
                    <param-name>locatorFactorySelector</param-name>
                    <param-value>classpath*:beanRefContext.xml</param-value>
                </context-param>
                <context-param>
                    <param-name>parentContextKey</param-name>
                    <param-value>app.context</param-value>
                </context-param>
                <listener>
                    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
                </listener>
            now when i deploy the ear it start the parentContextKey which refers to the business layer context, then it fails with the following message:

            Code:
            java.lang.IllegalStateException: ClassLoader [org.apache.catalina.loader.WebappClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:spring-agent.jar
                    at org.springframework.context.weaving.DefaultContextLoadTimeWeaver.setBeanClassLoader(DefaultContextLoadTimeWeaver.java:82)
                    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1321)
                    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
                    ... 131 more
            My WEB-INF/lib folder is empty cause i've used the maven war skinny trick and all the jars are in the ear lib folder.
            I think it's a classloader problem: Spring jars should be loaded by the ear classloader but actually are loaded by the war classloader as stated in the stacktrace.

            I still haven't found a solution.

            regards

            Domenico
            Last edited by domgif; Nov 18th, 2008, 11:23 AM. Reason: facing the same issue

            Comment

            Working...
            X