Spring JTA TransactionManager config: Supporting both Tomcat and JBoss
Asked Answered
W

5

10

I have a web application using JPA and JTA with Spring. I would like to support both JBoss and Tomcat. When running on JBoss, I'd like to use JBoss' own TransactionManager, and when running on Tomcat, I'd like to use JOTM.

I have both scenarios working, but I now find that I seem to need two separate Spring configurations for the two cases. With JOTM, I need to use Spring's JotmFactoryBean:

<bean id="transactionManager" 
 class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="userTransaction">
        <bean class="org.springframework.transaction.jta.JotmFactoryBean"/>
    </property>
</bean>

In JBoss, though, I just need to fetch "TransactionManager" from JNDI:

<bean id="transactionManager" 
 class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager">
        <bean class="org.springframework.jndi.JndiObjectFactoryBean">
             <property name="resourceRef" value="true" />
             <property name="jndiName" value="TransactionManager" />
             <property name="expectedType" 
               value="javax.transaction.TransactionManager" />
        </bean>
    </property>
</bean>

Is there a way to configure this so that the appropriate TransactionManager - JBoss or JOTM - is used, without the need for two different configuration files?

Wynnie answered 22/9, 2008 at 21:27 Comment(1)
Spring 3 no longer provides the org.springframework.transaction.jta.JotmFactoryBean class, so you may need to copy the source from 2.5.x.Horologe
C
14

I think you have missed the point of JNDI. JNDI was pretty much written to solve the problem you have!

I think you can take it up a level, so instead of using the "userTransaction" or "transactionManager from JNDI" depending on your situation. Why not add the "JtaTransactionManager" to JNDI. That way you push the configuration to the JNDI where it is supposed to be instead of creating even more configuration files [ like there aren't enough already ;) ].

Challah answered 6/1, 2009 at 15:33 Comment(0)
T
4

You can use PropertyConfigurerPlaceholder to inject bean references as well as simple values.

For example if you call your beans 'jotm' and 'jboss' then you could inject your TM like:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE">
    <property name="location" value="classpath:/path/to/application.properties"/>
</bean>
<bean id="jotm">...</bean>
<bean id="jboss">...</bean>
<bean id="bean-requiring-transaction-manager">
    <property name="transactionManager" ref="${transaction.strategy}"/>
</bean>

Then you can swap transaction managers using

  • transaction.strategy=jotm in a properties file
  • -Dtransaction.strategy=jotm as a system property

This is one possible approach. See my blog for a more complete example.

Hope this helps.

Threepence answered 22/9, 2008 at 21:51 Comment(0)
P
2

If you are using Spring 2.5 you can use <tx:jta-transaction-manager/>. I have not used it with JBoss but it should work for you according to section 9.8 Application server-specific integration from the Spring reference manual.

Pycnidium answered 22/9, 2008 at 22:8 Comment(0)
R
2

The <tx:jta-transaction-manager/> approach will look for a transaction manager in several default locations listed here. If your JBoss transaction manager is not in one of those locations, I suggest you move it, if possible, or move it in Tomcat so that both containers have their TM in the same JNDI location.

Ramsey answered 4/11, 2008 at 19:40 Comment(0)
C
1

Just adding my experience here so I don't have to re-suffer the experience again.

As bmatthews68, Chochos and these posters have said, use <tx:jta-transaction-manager/> in your Spring bean file; it definitely provides the appropriate level of abstraction and there's no need to do anything extra on the Spring side.

As for Tomcat, I declared <Transaction factory="org.objectweb.jotm.UserTransactionFactory" jotm.timeout="60" /> in the default/shared conf/context.xml file, which binds to java:comp/UserTransaction. As this is one of the places searched for by Spring, you shouldn't need to do anything else.

One gotcha though: if like me you use Maven, make sure you exclude any dependencies on the javax.transaction:jta jar or set the scope to provided. Otherwise you will experience classloader issues.

Chuff answered 22/2, 2011 at 16:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.