Uploaded image for project: 'ActiveMQ Classic'
  1. ActiveMQ Classic
  2. AMQ-303

Pooled XAConnectionFactory for use with Spring



    • Improvement
    • Status: Closed
    • Minor
    • Resolution: Won't Fix
    • None
    • None
    • None
    • ActiveMQ 3


      Work is currently underway to provide a JCA Container implementation for Spring, which would allow fully transaction aware usage of ActiveMQ in Spring. Current Spring JCA Container implementations work well for consumers, but are not quite mature for producers. I've thrown together (as in, just a couple hours of work) an implementation of XAConnectionFactory that is both pooled and automatically detects and participates in surrounding JTA transactions. There are some caveats to this, however:
      1. This is considered a temporary solution until Spring JCA Container implementations have matured to the point where one can access pooled producers that automatically participate in the (optional) surrounding JTA transaction, even if the transaction was started by a 3rd party (as opposed to being started by ActiveMQ in response to consuming a message).
      2. This was thrown together by copying out ActiveMQ's PooledConnectionFactory code and modifying as needed. Because of this, there is much code duplication between PooledConnectionFactory and PooledSpringXAConnectionFactory. Also, the code ends up being ugly.
      3. This implementation depends on both JTA and Spring. It requires JTA in order to properly enlist and handle XA connections/sessions/etc, and it requires Spring in order to manage XASession resources associated with the current transaction.
      4. We are still in the process of testing this code. We are moving our current code base to Spring 1.2.2 as we need some of the transaction bug fixes made in 1.2.2. Until we are fully ported, we will not be able to fully test this code. If we run into problems/bugs, we will post updates to this JIRA issue.

      With all that out of the way, usage is very similar to PooledConnectionFactory. First, I'll comment on usage, and then show a sample Spring configuration.
      As far as usage is concerned, you must not hold onto sessions and/or producers for long periods of time, especially across transaction boundaries. In other words, do not write code that opens a session and then leaves it open for the duration of your application. Instead, your code should do this every time it needs to produce:
      1. Open a new connection: connectionFactory.createConnection().
      2. Create a new session: connection.createSessions(...)
      3. Create a producer: session.createProducer(...)
      4. Produce messages
      5. close producer, close session, close connection.

      This pattern may seem heavyweight, but because you are using PooledSpringXAConnectionFactory, it is actually quite light and efficient. The following will hold true if you use this pattern:

      1. You will be using pooled connections, sessions, and producers - so you will be avoiding the cost of opening/creating them every time, even though you are calling "create" and "close" methods.
      2. These sessions will automatically participate in any surrounding JTA transaction.
      3. All these objects will be properly managed for thread safety.
      4. If there is a surrounding JTA transaction, then for each thread, the same actual XASession will be used for the remainder of the transaction.

      Finally, here is an example Spring configuration:

      <!-- This bean automatically handles pooling and transaction management -->
      <bean id="jmsConnectionFactory" class="com.marathon.jms.PooledSpringXAConnectionFactory">
      <property name="connectionFactory">
      <!-- Actual transaction aware connection factory. -->
      <bean class="org.activemq.ActiveMQXAConnectionFactory">
      <property name="brokerURL"><value>... broker URL goes here ...</value></property>
      <property name="jtaTransactionManager" ref="transactionManager"/>

      Note that PooledSpringXAConnectionFactory needs access to a JTA TransactionManager, and there are two ways to provide it. If you have exposed the actual JTA javax.transaction.TransactionManager as a bean in your Spring config, then you would set the "transactionManager" property:
      <property name="transactionManager" ref="beanNameOfTransactionManager"/>
      If you have exposed a Spring org.springframework.transaction.jta.JtaTransactionManager in your config, then you could set the "jtaTransactionManager" property:
      <property name="jtaTransactionManager" ref="beanNameOfSpringJtaTransactionManager"/>
      Either way will allow PooledSpringXAConnectionFactory to get access to the JTA TransactionManager. You only need to set one of these properties.




            jstrachan James Strachan
            adepue Andy DePue
            1 Vote for this issue
            1 Start watching this issue