You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-user@axis.apache.org by David Bunzli <Da...@health.qld.gov.au> on 2008/05/26 03:59:18 UTC

Getting Spring & Hibernate to work in AARs

Hi all,
 
I have been having no end of problems getting Spring & Hibernate to work in AARs. The basis for the problems was getting Hibernate to find the mapping files and data access objects because of the classpath.
 
I followed the advice given in http://ws.apache.org/axis2/1_4/spring.html#263 with some success, but I had to explode my AAR so that only the service related files (eg services.xml, the WSDL and the Spring configuration file) were in the AAR. The rest of the files (including the Hibernate mapping files and data access objects) were in a JAR deployed in <webapps>/axis2/WEB-INF/lib. Not ideal.
 
In the end it appears the issue I was having was with caused by using Spring's ProxyFactoryBean having problems loading the Hibernate DAO classes from within the AAR. This is caused by Spring using the WEB-APP classloader and therefore not looking at the AAR (which is not on the WEB-APP's classpath).
 
My solution involves modifying the class which initialises Spring within the AAR. (http://ws.apache.org/axis2/1_4/spring.html#262)
 
I've posted this in the hope that it assists someone else with what probably is a common problem.
 
Relevant parts of the Spring configuration file...
 
    <!-- the way to point to the Hibernate mapping files -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="namingStrategy">
            <ref bean="namingStrategy"/>
        </property>
        <property name="mappingJarLocations">
         <list>
          <value>file:/<webServerPath>/webapps/axis2/WEB-INF/services/Service.aar</value>
         </list>
        </property>
 
    <!-- the ProxyFactoryBean declaration which was causing classpath issues. This is referenced by the Hibernate DAOs -->
    <bean id="abstractDao"
          class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true">
        <property name="interceptorNames">
            <list>
                <value>finderIntroductionAdvisor</value>
            </list>
        </property>
    </bean>
 
    <!-- the Hibernate DAO declaration referencing Spring's ProxyFactoryBean -->
    <bean id="transactionDao" parent="abstractDao">
     <property name="proxyInterfaces">
      <value><packageComponent>.TransactionDao</value>
     </property>
     <property name="target">
      <bean parent="abstractDaoTarget">
       <constructor-arg>
        <value><packageComponent>.domain.Transaction</value>
       </constructor-arg>
      </bean>
     </property>
    </bean>
 
Here is the modification to the Spring initialising class to make things work...
 
   public void startUp(ConfigurationContext ignore, AxisService service) {       
       /* 
           If you use a Spring ProxyFactoryBean and proxyInterface, Spring has issues loading the Hibernate DAO classes from within the AAR. 
           This is caused by Spring using the WEB-APP classloader and therefore not looking at the AAR (which is not on the WEB-APP's classpath) 
           The solution is in 3 parts
           a) get the current thread
           b) load the Spring stuff using the service's classloader
           c) change back to the current thread's (ie the WEB-APP's) classloader to reduce the possibility of unexpected side-effects
       */ 
       // Part A
       ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
       // Part B
       ClassLoader classLoader = service.getClassLoader();
       Thread.currentThread().setContextClassLoader(classLoader);
       
       ClassPathXmlApplicationContext appCtx = 
           new ClassPathXmlApplicationContext(
               new String[]{ "applicationContext.xml"}, false );
       
       appCtx.setClassLoader(classLoader);
       appCtx.refresh();
       
       // Part C
       Thread.currentThread().setContextClassLoader(contextCl);
   }
 
 
Good luck,
David

********************************************************************************
This email, including any attachments sent with it, is confidential and for the sole use of the intended recipient(s). This confidentiality is not waived or lost, if you receive it and you are not the intended recipient(s), or if it is transmitted/received in error.
Any unauthorised use, alteration, disclosure, distribution or review of this email is strictly prohibited.  The information contained in this email, including any attachment sent with it, may be subject to a statutory duty of confidentiality if it relates to health service matters.
If you are not the intended recipient(s), or if you have received this email in error, you are asked to immediately notify the sender by telephone collect on Australia +61 1800 198 175 or by return email.  You should also delete this email, and any copies, from your computer system network and destroy any hard copies produced.
If not an intended recipient of this email, you must not copy, distribute or take any action(s) that relies on it; any form of disclosure, modification, distribution and/or publication of this email is also prohibited.
Although Queensland Health takes all reasonable steps to ensure this email does not contain malicious software, Queensland Health does not accept responsibility for the consequences if any person's computer inadvertently suffers any disruption to services, loss of information, harm or is infected with a virus, other malicious computer programme or code that may occur as a consequence of receiving this email.
Unless stated otherwise, this email represents only the views of the sender and not the views of the Queensland Government.
**********************************************************************************


Re: Getting Spring & Hibernate to work in AARs

Posted by robert lazarski <ro...@gmail.com>.
AAR's use a different classloader then the TCCL and therefore can't
load hibernates xml files inside them. Therefore, hbm files need to be
placed somewhere inside one of the classpaths, or set via :

http://www.springframework.org/docs/api/org/springframework/orm/hibernate/LocalSessionFactoryBean.html#setMappingDirectoryLocations(org.springframework.core.io.Resource[])

That does not need to be WEB-INF/lib, but any known classpath
location. Furthermore, the curveball you're throwing is using
org.springframework.aop.framework.ProxyFactoryBean instead of
ApplicationContext.

At a glance, the code you have in startup() is user level and while it
may work in your case, but IIRC is pretty much the axis2 internal API
code that created http://issues.apache.org/jira/browse/AXIS2-1214 .

In short: the AAR classloader and the TCCL which spring / hibernate
depend on require's what we have now in the internal API's to even get
these to play nice at at all - without breaking other stuff like
classic java InitialContext. I've been waiting for some clever
individual to submit patches that solves all this in its entirety -
but so far that won't be me as it just "works" for what I need Spring
/ Hibernate / Axis2 to do. Taking a look at AbstractMessageReceiver in
its current state, and the amount of Classloader declarations that
lurk in the code base and the amount of things that are breakable,
seems like a user space solution like the one you have or living with
finding hbm files in the classpath is the easy way out.

HTH,
Robert

On Sun, May 25, 2008 at 10:59 PM, David Bunzli
<Da...@health.qld.gov.au> wrote:
> Hi all,
>
> I have been having no end of problems getting Spring & Hibernate to work in
> AARs. The basis for the problems was getting Hibernate to find the mapping
> files and data access objects because of the classpath.
>
> I followed the advice given in
> http://ws.apache.org/axis2/1_4/spring.html#263 with some success, but I had
> to explode my AAR so that only the service related files (eg services.xml,
> the WSDL and the Spring configuration file) were in the AAR. The rest of the
> files (including the Hibernate mapping files and data access objects) were
> in a JAR deployed in <webapps>/axis2/WEB-INF/lib. Not ideal.
>
> In the end it appears the issue I was having was with caused by using
> Spring's ProxyFactoryBean having problems loading the Hibernate DAO classes
> from within the AAR. This is caused by Spring using the WEB-APP classloader
> and therefore not looking at the AAR (which is not on the WEB-APP's
> classpath).
>
> My solution involves modifying the class which initialises Spring within the
> AAR. (http://ws.apache.org/axis2/1_4/spring.html#262)
>
> I've posted this in the hope that it assists someone else with what probably
> is a common problem.
>
> Relevant parts of the Spring configuration file...
>
>     <!-- the way to point to the Hibernate mapping files -->
>     <bean id="sessionFactory"
> class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
>         <property name="namingStrategy">
>             <ref bean="namingStrategy"/>
>         </property>
>         <property name="mappingJarLocations">
>          <list>
>
>   <value>file:/<webServerPath>/webapps/axis2/WEB-INF/services/Service.aar</value>
>          </list>
>         </property>
>
>     <!-- the ProxyFactoryBean declaration which was causing classpath
> issues. This is referenced by the Hibernate DAOs -->
>     <bean id="abstractDao"
>           class="org.springframework.aop.framework.ProxyFactoryBean"
> abstract="true">
>         <property name="interceptorNames">
>             <list>
>                 <value>finderIntroductionAdvisor</value>
>             </list>
>         </property>
>     </bean>
>
>     <!-- the Hibernate DAO declaration referencing Spring's ProxyFactoryBean
> -->
>     <bean id="transactionDao" parent="abstractDao">
>      <property name="proxyInterfaces">
>       <value><packageComponent>.TransactionDao</value>
>      </property>
>      <property name="target">
>       <bean parent="abstractDaoTarget">
>        <constructor-arg>
>         <value><packageComponent>.domain.Transaction</value>
>        </constructor-arg>
>       </bean>
>      </property>
>     </bean>
>
> Here is the modification to the Spring initialising class to make things
> work...
>
>    public void startUp(ConfigurationContext ignore, AxisService service)
> {
>        /*
>            If you use a Spring ProxyFactoryBean and proxyInterface, Spring
> has issues loading the Hibernate DAO classes from within the AAR.
>            This is caused by Spring using the WEB-APP classloader and
> therefore not looking at the AAR (which is not on the WEB-APP's classpath)
>            The solution is in 3 parts
>            a) get the current thread
>            b) load the Spring stuff using the service's classloader
>            c) change back to the current thread's (ie the WEB-APP's)
> classloader to reduce the possibility of unexpected side-effects
>        */
>        // Part A
>        ClassLoader contextCl =
> Thread.currentThread().getContextClassLoader();
>        // Part B
>        ClassLoader classLoader = service.getClassLoader();
>        Thread.currentThread().setContextClassLoader(classLoader);
>
>        ClassPathXmlApplicationContext appCtx =
>            new ClassPathXmlApplicationContext(
>                new String[]{ "applicationContext.xml"}, false );
>
>        appCtx.setClassLoader(classLoader);
>        appCtx.refresh();
>
>        // Part C
>        Thread.currentThread().setContextClassLoader(contextCl);
>    }
>
>
> Good luck,
> David
>
> ********************************************************************************
>
> This email, including any attachments sent with it, is confidential and for
> the sole use of the intended recipient(s). This confidentiality is not
> waived or lost, if you receive it and you are not the intended recipient(s),
> or if it is transmitted/received in error.
>
> Any unauthorised use, alteration, disclosure, distribution or review of this
> email is strictly prohibited. The information contained in this email,
> including any attachment sent with it, may be subject to a statutory duty of
> confidentiality if it relates to health service matters.
>
> If you are not the intended recipient(s), or if you have received this email
> in error, you are asked to immediately notify the sender by telephone
> collect on Australia +61 1800 198 175 or by return email. You should also
> delete this email, and any copies, from your computer system network and
> destroy any hard copies produced.
>
> If not an intended recipient of this email, you must not copy, distribute or
> take any action(s) that relies on it; any form of disclosure, modification,
> distribution and/or publication of this email is also prohibited.
>
> Although Queensland Health takes all reasonable steps to ensure this email
> does not contain malicious software, Queensland Health does not accept
> responsibility for the consequences if any person's computer inadvertently
> suffers any disruption to services, loss of information, harm or is infected
> with a virus, other malicious computer programme or code that may occur as a
> consequence of receiving this email.
>
> Unless stated otherwise, this email represents only the views of the sender
> and not the views of the Queensland Government.
>
> **********************************************************************************
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: axis-user-unsubscribe@ws.apache.org
For additional commands, e-mail: axis-user-help@ws.apache.org