Support mixed XA/non-XA ConnectionFactory beans

Update ActiveMQ and HornetQ XA configurations to also expose non-xa
ConnectionFactory variants.

Fixes gh-1461
pull/1492/head
Phillip Webb 10 years ago
parent 57a154520e
commit 236026a43a

@ -19,13 +19,16 @@ package org.springframework.boot.autoconfigure.jms.activemq;
import javax.jms.ConnectionFactory;
import javax.transaction.TransactionManager;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.ActiveMQXAConnectionFactory;
import org.apache.activemq.pool.PooledConnectionFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* Configuration for ActiveMQ XA {@link ConnectionFactory}.
@ -39,7 +42,8 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnMissingBean(ConnectionFactory.class)
class ActiveMQXAConnectionFactoryConfiguration {
@Bean
@Primary
@Bean(name = { "jmsConnectionFactory", "xaJmsConnectionFactory" })
public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,
XAConnectionFactoryWrapper wrapper) throws Exception {
ActiveMQXAConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
@ -47,4 +51,16 @@ class ActiveMQXAConnectionFactoryConfiguration {
return wrapper.wrapConnectionFactory(connectionFactory);
}
@Bean
public ConnectionFactory nonXaJmsConnectionFactory(ActiveMQProperties properties) {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
properties).createConnectionFactory(ActiveMQConnectionFactory.class);
if (properties.isPooled()) {
PooledConnectionFactory pool = new PooledConnectionFactory();
pool.setConnectionFactory(connectionFactory);
return pool;
}
return connectionFactory;
}
}

@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.jms.hornetq;
import javax.jms.ConnectionFactory;
import javax.transaction.TransactionManager;
import org.hornetq.jms.client.HornetQConnectionFactory;
import org.hornetq.jms.client.HornetQXAConnectionFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@ -27,6 +28,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* Configuration for HornetQ XA {@link ConnectionFactory}.
@ -40,7 +42,8 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnBean(XAConnectionFactoryWrapper.class)
class HornetQXAConnectionFactoryConfiguration {
@Bean
@Primary
@Bean(name = { "jmsConnectionFactory", "xaJmsConnectionFactory" })
public ConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory,
HornetQProperties properties, XAConnectionFactoryWrapper wrapper)
throws Exception {
@ -49,4 +52,10 @@ class HornetQXAConnectionFactoryConfiguration {
.createConnectionFactory(HornetQXAConnectionFactory.class));
}
@Bean
public ConnectionFactory nonXaJmsConnectionFactory(ListableBeanFactory beanFactory,
HornetQProperties properties) {
return new HornetQConnectionFactoryFactory(beanFactory, properties)
.createConnectionFactory(HornetQConnectionFactory.class);
}
}

@ -1964,6 +1964,38 @@ to configure your `DataSource`.
=== Mixing XA and non-XA JMS connections
When using JTA, the primary JMS `ConnectionFactory` bean will be XA aware and participate
in distributed transactions. In some situations you might want to process certain JMS
messages using a non-XA `ConnectionFactory`. For example, your JMS processing logic might
take longer than the XA timeout.
If you want to use a non-XA `ConnectionFactory` you can inject the
`nonXaJmsConnectionFactory` bean rather than the `@Primary` `jmsConnectionFactory` bean.
For consistency the `jmsConnectionFactory` bean is also provided using the bean alias
`xaJmsConnectionFactory`.
For example:
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
// Inject the primary (XA aware) ConnectionFactory
@Autowired
private ConnectionFactory defaultConnectionFactory;
// Inject the XA aware ConnectionFactory (uses the alias and injects the same as above)
@Autowired
@Qualifier("xaJmsConnectionFactory")
private ConnectionFactory xaConnectionFactory;
// Inject the non-XA aware ConnectionFactory
@Autowired
@Qualifier("nonXaJmsConnectionFactory")
private ConnectionFactory nonXaConnectionFactory;
----
=== Supporting an alternative embedded transaction manager
The {sc-spring-boot}/jta/XAConnectionFactoryWrapper.{sc-ext}[`XAConnectionFactoryWrapper`]
and {sc-spring-boot}/jta/XADataSourceWrapper.{sc-ext}[`XADataSourceWrapper`] interfaces

@ -20,8 +20,15 @@ import org.hamcrest.Matcher;
import org.hamcrest.core.SubstringMatcher;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.test.OutputCapture;
import org.springframework.context.ApplicationContext;
import bitronix.tm.resource.jms.PoolingConnectionFactory;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
/**
@ -44,6 +51,19 @@ public class SampleBitronixApplicationTests {
assertThat(output, containsString(1, "Simulated error"));
}
@Test
public void testExposesXaAndNonXa() throws Exception {
ApplicationContext context = SpringApplication
.run(SampleBitronixApplication.class);
Object jmsConnectionFactory = context.getBean("jmsConnectionFactory");
Object xaJmsConnectionFactory = context.getBean("xaJmsConnectionFactory");
Object nonXaJmsConnectionFactory = context.getBean("nonXaJmsConnectionFactory");
assertThat(jmsConnectionFactory, sameInstance(xaJmsConnectionFactory));
assertThat(jmsConnectionFactory, instanceOf(PoolingConnectionFactory.class));
assertThat(nonXaJmsConnectionFactory,
not(instanceOf(PoolingConnectionFactory.class)));
}
private Matcher<? super String> containsString(final int times, String s) {
return new SubstringMatcher(s) {

Loading…
Cancel
Save