Support mixed XA/non-XA ConnectionFactory beans
Update ActiveMQ and HornetQ XA configurations to also expose non-xa ConnectionFactory variants. Fixes gh-1461
This commit is contained in:
parent
57a154520e
commit
236026a43a
|
|
@ -19,13 +19,16 @@ package org.springframework.boot.autoconfigure.jms.activemq;
|
||||||
import javax.jms.ConnectionFactory;
|
import javax.jms.ConnectionFactory;
|
||||||
import javax.transaction.TransactionManager;
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.apache.activemq.ActiveMQConnectionFactory;
|
||||||
import org.apache.activemq.ActiveMQXAConnectionFactory;
|
import org.apache.activemq.ActiveMQXAConnectionFactory;
|
||||||
|
import org.apache.activemq.pool.PooledConnectionFactory;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
|
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for ActiveMQ XA {@link ConnectionFactory}.
|
* Configuration for ActiveMQ XA {@link ConnectionFactory}.
|
||||||
|
|
@ -39,7 +42,8 @@ import org.springframework.context.annotation.Configuration;
|
||||||
@ConditionalOnMissingBean(ConnectionFactory.class)
|
@ConditionalOnMissingBean(ConnectionFactory.class)
|
||||||
class ActiveMQXAConnectionFactoryConfiguration {
|
class ActiveMQXAConnectionFactoryConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Primary
|
||||||
|
@Bean(name = { "jmsConnectionFactory", "xaJmsConnectionFactory" })
|
||||||
public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,
|
public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,
|
||||||
XAConnectionFactoryWrapper wrapper) throws Exception {
|
XAConnectionFactoryWrapper wrapper) throws Exception {
|
||||||
ActiveMQXAConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
|
ActiveMQXAConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
|
||||||
|
|
@ -47,4 +51,16 @@ class ActiveMQXAConnectionFactoryConfiguration {
|
||||||
return wrapper.wrapConnectionFactory(connectionFactory);
|
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.jms.ConnectionFactory;
|
||||||
import javax.transaction.TransactionManager;
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hornetq.jms.client.HornetQConnectionFactory;
|
||||||
import org.hornetq.jms.client.HornetQXAConnectionFactory;
|
import org.hornetq.jms.client.HornetQXAConnectionFactory;
|
||||||
import org.springframework.beans.factory.ListableBeanFactory;
|
import org.springframework.beans.factory.ListableBeanFactory;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
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.boot.jta.XAConnectionFactoryWrapper;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for HornetQ XA {@link ConnectionFactory}.
|
* Configuration for HornetQ XA {@link ConnectionFactory}.
|
||||||
|
|
@ -40,7 +42,8 @@ import org.springframework.context.annotation.Configuration;
|
||||||
@ConditionalOnBean(XAConnectionFactoryWrapper.class)
|
@ConditionalOnBean(XAConnectionFactoryWrapper.class)
|
||||||
class HornetQXAConnectionFactoryConfiguration {
|
class HornetQXAConnectionFactoryConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Primary
|
||||||
|
@Bean(name = { "jmsConnectionFactory", "xaJmsConnectionFactory" })
|
||||||
public ConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory,
|
public ConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory,
|
||||||
HornetQProperties properties, XAConnectionFactoryWrapper wrapper)
|
HornetQProperties properties, XAConnectionFactoryWrapper wrapper)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
@ -49,4 +52,10 @@ class HornetQXAConnectionFactoryConfiguration {
|
||||||
.createConnectionFactory(HornetQXAConnectionFactory.class));
|
.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
|
=== Supporting an alternative embedded transaction manager
|
||||||
The {sc-spring-boot}/jta/XAConnectionFactoryWrapper.{sc-ext}[`XAConnectionFactoryWrapper`]
|
The {sc-spring-boot}/jta/XAConnectionFactoryWrapper.{sc-ext}[`XAConnectionFactoryWrapper`]
|
||||||
and {sc-spring-boot}/jta/XADataSourceWrapper.{sc-ext}[`XADataSourceWrapper`] interfaces
|
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.hamcrest.core.SubstringMatcher;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.test.OutputCapture;
|
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;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -44,6 +51,19 @@ public class SampleBitronixApplicationTests {
|
||||||
assertThat(output, containsString(1, "Simulated error"));
|
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) {
|
private Matcher<? super String> containsString(final int times, String s) {
|
||||||
return new SubstringMatcher(s) {
|
return new SubstringMatcher(s) {
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue