Primavera JTA TransactionManager config: Suportando tanto Tomcat e JBoss
Pergunta
Tenho uma aplicação web usando JPA e JTA com Spring. Gostaria de apoiar tanto JBoss e Tomcat. Quando em execução no JBoss, eu gostaria de usar o próprio TransactionManager JBoss', e quando executado em Tomcat, eu gostaria de usar JOTM.
Eu tenho ambos os cenários de trabalho, mas agora eu acho que eu parecem precisar de duas configurações do Spring separadas para os dois casos. Com JOTM, eu preciso usar JotmFactoryBean
da Primavera:
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction">
<bean class="org.springframework.transaction.jta.JotmFactoryBean"/>
</property>
</bean>
No JBoss, porém, eu só preciso buscar "TransactionManager" de 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>
Existe uma maneira de configurar isso para que o TransactionManager apropriado - JBoss ou JOTM -? É usado, sem a necessidade de dois arquivos de configuração diferentes
Solução
Eu acho que você perdeu o ponto de JNDI. JNDI foi praticamente escrito para resolver o problema que você tem!
Eu acho que você pode levá-lo até um nível, de modo que em vez de usar o "UserTransaction" ou "transactionManager de JNDI" dependendo da sua situação. Por que não adicionar o "JtaTransactionManager" para JNDI. Dessa forma, você empurrar a configuração para o JNDI onde é suposto ser em vez de criar ainda mais arquivos de configuração [como não há o suficiente já;)].
Outras dicas
Você pode usar PropertyConfigurerPlaceholder para referências de bean injetar, bem como valores simples.
Por exemplo, se você ligar o seu feijão 'JOTM' e 'jboss', então você pode injetar sua TM como:
<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>
Em seguida, você pode trocar gerenciadores de transações usando
- transaction.strategy = JOTM em um arquivo de propriedades
- -Dtransaction.strategy = JOTM como uma propriedade do sistema
Esta é uma abordagem possível. Ver o meu blogue para um exemplo mais completo .
Espero que isso ajude.
A abordagem <tx:jta-transaction-manager/>
irá procurar um gerenciador de transações em vários locais padrão aqui . Se o seu gerenciador de transações JBoss não está em um desses locais, sugiro que você movê-lo, se possível, ou movê-lo no Tomcat para que ambos os recipientes têm a sua TM no mesmo local JNDI.
Basta adicionar minha experiência aqui, então eu não tenho que re-sofrer a experiência novamente.
Como bmatthews68, chochos e esses cartazes ter dito, uso <tx:jta-transaction-manager/>
em seu arquivo bean Spring; ele definitivamente proporciona o nível apropriado de abstração e não há necessidade de fazer nada extra no lado do Primavera.
Quanto Tomcat, declarei <Transaction factory="org.objectweb.jotm.UserTransactionFactory" jotm.timeout="60" />
no arquivo conf/context.xml
default / compartilhada, que se liga a java:comp/UserTransaction
. Como este é um dos lugares procurou por Spring, você não precisa fazer mais nada.
Uma pegadinha no entanto: se gosta de mim você usa Maven, certifique-se de excluir quaisquer dependências no frasco javax.transaction:jta
ou definir o escopo para provided
. Caso contrário, você vai ter problemas de carregador de classe.