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.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…
Reference in New Issue