问题描述:

Attempting to get transactions to work using Tomcat, Atomikos, ActiveMQ, and MySql. Followed these examples:

Tomcat 7 Integration with Atomikos 3.5.2

and Tomcat 7.0.27 Integration with Atomikos 3.7.1 with no success...

ERROR: com.atomikos.icatch.jta.UserTransactionManager cannot be cast to javax.transaction.TransactionManager

java.lang.ClassCastException: com.atomikos.icatch.jta.UserTransactionManager cannot be cast to javax.transaction.TransactionManager

Using:

  • Tomcat 7.0.29
  • Atomikos 3.7.1
  • ActiveMQ 5.8.0
  • MySQL 5.5.31

Dropped the following jars under $TOMCAT_HOME/lib

  • atomikos-integration-extension-3.7.1-20120529.jar
  • atomikos-util-3.7.1.jar
  • transactions-3.7.1.jar
  • transactions-api-3.7.1.jar
  • transactions-jdbc-3.7.1.jar
  • transactions-jms-3.7.1.jar
  • transactions-jta-3.7.1.jar
  • geronimo-jta_1.0.1B_spec-1.0.jar
  • activemq-all-5.8.0.jar
  • mysql-connector-java-5.1.25.jar

Here are the contents of transactions.properties

com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory

com.atomikos.icatch.automatic_resource_registration=true

com.atomikos.icatch.output_dir=../work/atomikos

com.atomikos.icatch.log_base_dir=../work/atomikos/log

com.atomikos.icatch.enable_logging=true

com.atomikos.icatch.console_log_level=TRACE

context.xml

 <?xml version="1.0" encoding="UTF-8"?>

<Context>

<WatchedResource>WEB-INF/web.xml</WatchedResource>

<Transaction factory="com.atomikos.icatch.jta.UserTransactionFactory" />

<Resource name="TransactionManager"

auth="Container"

type="com.atomikos.icatch.jta.UserTransactionManager"

factory="org.apache.naming.factory.BeanFactory" />

<Resource name="UserTransaction"

auth="Container"

type="com.atomikos.icatch.jta.UserTransactionImp"

factory="org.apache.naming.factory.BeanFactory" />

<Resource name="jms/ConnectionFactory"

auth="Container"

description="JMS Connection Factory"

type="com.atomikos.jms.AtomikosConnectionFactoryBean"

factory="com.atomikos.tomcat.EnhancedTomcatAtomikosBeanFactory"

uniqueResourceName="jms/ConnectionFactory"

xaConnectionFactoryClassName="org.apache.activemq.ActiveMQXAConnectionFactory"

xaProperties.brokerURL="vm://localhost"

xaProperties.transportType="1"

localTransactionMode="true" />

<Resource name="jms/WsTopic"

auth="Container"

type="org.apache.activemq.command.ActiveMQTopic"

factory="org.apache.activemq.jndi.JNDIReferenceFactory"

physicalName="WS.TOPIC" />

<Resource name="jms/WsQueue"

auth="Container"

type="org.apache.activemq.command.ActiveMQQueue"

factory="org.apache.activemq.jndi.JNDIReferenceFactory"

physicalName="WS.QUEUE" />

<!-- MySQL -->

<Resource name="jdbc/DB"

auth="Container"

type="com.atomikos.jdbc.AtomikosDataSourceBean"

factory="com.atomikos.tomcat.EnhancedTomcatAtomikosBeanFactory"

uniqueResourceName="jdbc/DB"

minPoolSize="5"

maxPoolSize="10"

testQuery="SELECT 1 FROM DUAL"

xaDataSourceClassName="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"

xaProperties.databaseName="db"

xaProperties.serverName="localhost"

xaProperties.port="3306"

xaProperties.user="user"

xaProperties.password="password"

xaProperties.url="jdbc:mysql://localhost:3306/db"

xaProperties.pinGlobalTxToPhysicalConnection="true"

xaProperties.autoReconnect="true"

xaProperties.autoReconnectForConnectionPools="true"

xaProperties.autoReconnectForPools="true" />

</Context>

Relevant java code:

import javax.transaction.Transaction;

import javax.transaction.TransactionManager;

import javax.transaction.UserTransaction;

...

Hashtable<String, String> hashTable = new Hashtable<String, String>();

try {

Context ctx = new InitialContext(hashTable);

ctx = (Context) jndiContext.lookup("java:comp/env");

TransactionManager transactionManager = (TransactionManager) ctx.lookup("TransactionManager");

} catch (Exception e) {

e.printStackTrace();

}

What am I doing wrong?

EDIT:

After removing activemq-all-5.8.0.jar from $TOMCAT_HOME/lib, I was able to get past the original error, but now I'm getting:

com.atomikos.jms.AtomikosJMSException: Error in proxy

at com.atomikos.jms.AtomikosJMSException.throwAtomikosJMSException(AtomikosJMSException.java:54)

at com.atomikos.jms.ConsumerProducerSupport.handleException(ConsumerProducerSupport.java:61)

at com.atomikos.jms.AtomikosJmsMessageConsumerProxy.receive(AtomikosJmsMessageConsumerProxy.java:73)

at com.atomikos.jms.AtomikosJmsMessageConsumerProxy.receive(AtomikosJmsMessageConsumerProxy.java:137)

...

at java.lang.Thread.run(Thread.java:619)

Caused by: com.atomikos.jms.AtomikosTransactionRequiredJMSException: The JMS session you are using requires a JTA transaction context for the calling thread and none was found.

Please correct your code to do one of the following:

1. start a JTA transaction if you want your JMS operations to be subject to JTA commit/rollback, or

2. increase the maxPoolSize of the AtomikosConnectionFactoryBean to avoid transaction timeout while waiting for a connection, or

3. create a non-transacted session and do session acknowledgment yourself, or

4. set localTransactionMode to true so connection-level commit/rollback are enabled.

at com.atomikos.jms.AtomikosTransactionRequiredJMSException.throwAtomikosTransactionRequiredJMSException(AtomikosTransactionRequiredJMSException.java:38)

at com.atomikos.jms.ConsumerProducerSupport.enlist(ConsumerProducerSupport.java:107)

at com.atomikos.jms.AtomikosJmsMessageConsumerProxy.receive(AtomikosJmsMessageConsumerProxy.java:70)

... 5 more

网友答案:

Tomcat uses multiple class-loaders. See their definitions, how it works and which takes the precedence (bootstrap, system, webapp, common). I assume you placed the geronimo-jta_1.0.1B_spec-1.0.jar and/or transactions-jta-3.7.1.jar inside the WAR file webapp.war/WEB-INF/lib/ in addition to $TOMCAT_HOME/lib/. This might cause issues as the javax.transaction.TransactionManager class will be loaded multiple times by different class-loaders. Even if the class has the same name, if it is loaded by different class-loaders, the cast fails.

  1. It is firstly loaded with common class-loader ($TOMCAT_HOME/lib/*.jar) when Tomcat initializes the container-wide TransactionManager resource defined in the context.xml implemented by com.atomikos.icatch.jta.UserTransactionManager. (Tomcat does not use any webapp class-loader at this time.)

  2. you use the javax.transaction.TransactionManager class in your web-application, now it will be loaded with webapp class-loader from a copy of the JAR file located in the webapp.war/WEB-INF/lib/ folder inside the WAR file.

Try to remove the JAR files containing the javax.transaction.TransactionManager class from the webapp.war/WEB-INF/lib/ and try to redeploy your application.

Alternatively, list these JAR files in the CLASSPATH system variable thus these classes will be loaded by the system class-loader that has precedence in Tomcat.

相关阅读:
Top