Skip to content

Commit 441049c

Browse files
committed
Auto-detect JMS sessionTransacted flag
If a JtaTransactionManager is present, it is associated with the auto-created JmsListenerContainerFactory. However, if no such transaction manager is present, local transaction support is not enabled. This gives a default situation where the message is acknowledged even before the listener is invoked. We now make sure to turn on local JMS transactions if no JtaTransactionManager is present. Fixes gh-3393
1 parent f4c95ea commit 441049c

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(
6161
if (this.transactionManager != null) {
6262
factory.setTransactionManager(this.transactionManager);
6363
}
64+
else {
65+
factory.setSessionTransacted(true);
66+
}
6467
if (this.destinationResolver != null) {
6568
factory.setDestinationResolver(this.destinationResolver);
6669
}

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@
2323
import org.junit.After;
2424
import org.junit.Test;
2525
import org.springframework.beans.BeansException;
26+
import org.springframework.beans.DirectFieldAccessor;
2627
import org.springframework.beans.factory.config.BeanPostProcessor;
2728
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
2829
import org.springframework.boot.test.EnvironmentTestUtils;
2930
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
3031
import org.springframework.context.annotation.Bean;
3132
import org.springframework.context.annotation.Configuration;
33+
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
3234
import org.springframework.jms.annotation.EnableJms;
3335
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
3436
import org.springframework.jms.config.JmsListenerConfigUtils;
@@ -38,10 +40,13 @@
3840
import org.springframework.jms.core.JmsMessagingTemplate;
3941
import org.springframework.jms.core.JmsTemplate;
4042
import org.springframework.jms.listener.DefaultMessageListenerContainer;
43+
import org.springframework.transaction.jta.JtaTransactionManager;
4144

4245
import static org.junit.Assert.assertEquals;
4346
import static org.junit.Assert.assertFalse;
4447
import static org.junit.Assert.assertNotNull;
48+
import static org.junit.Assert.assertNull;
49+
import static org.junit.Assert.assertSame;
4550
import static org.junit.Assert.assertTrue;
4651
import static org.mockito.Mockito.mock;
4752

@@ -137,6 +142,48 @@ public void testJmsListenerContainerFactoryBackOff() {
137142
jmsListenerContainerFactory.getClass());
138143
}
139144

145+
@Test
146+
public void testDefaultContainerFactoryWithJtaTransactionManager() {
147+
this.context = createContext(TestConfiguration7.class,
148+
EnableJmsConfiguration.class);
149+
JmsListenerContainerFactory<?> jmsListenerContainerFactory = this.context
150+
.getBean("jmsListenerContainerFactory", JmsListenerContainerFactory.class);
151+
assertEquals(DefaultJmsListenerContainerFactory.class,
152+
jmsListenerContainerFactory.getClass());
153+
DefaultMessageListenerContainer listenerContainer = ((DefaultJmsListenerContainerFactory)
154+
jmsListenerContainerFactory).createListenerContainer(mock(JmsListenerEndpoint.class));
155+
assertFalse("wrong session transacted flag with JTA transactions", listenerContainer.isSessionTransacted());
156+
assertSame(this.context.getBean(JtaTransactionManager.class),
157+
new DirectFieldAccessor(listenerContainer).getPropertyValue("transactionManager"));
158+
}
159+
160+
@Test
161+
public void testDefaultContainerFactoryNonJtaTransactionManager() {
162+
this.context = createContext(TestConfiguration8.class,
163+
EnableJmsConfiguration.class);
164+
JmsListenerContainerFactory<?> jmsListenerContainerFactory = this.context
165+
.getBean("jmsListenerContainerFactory", JmsListenerContainerFactory.class);
166+
assertEquals(DefaultJmsListenerContainerFactory.class,
167+
jmsListenerContainerFactory.getClass());
168+
DefaultMessageListenerContainer listenerContainer = ((DefaultJmsListenerContainerFactory)
169+
jmsListenerContainerFactory).createListenerContainer(mock(JmsListenerEndpoint.class));
170+
assertTrue("wrong session transacted flag with no tx manager", listenerContainer.isSessionTransacted());
171+
assertNull(new DirectFieldAccessor(listenerContainer).getPropertyValue("transactionManager"));
172+
}
173+
174+
@Test
175+
public void testDefaultContainerFactoryNoTransactionManager() {
176+
this.context = createContext(EnableJmsConfiguration.class);
177+
JmsListenerContainerFactory<?> jmsListenerContainerFactory = this.context
178+
.getBean("jmsListenerContainerFactory", JmsListenerContainerFactory.class);
179+
assertEquals(DefaultJmsListenerContainerFactory.class,
180+
jmsListenerContainerFactory.getClass());
181+
DefaultMessageListenerContainer listenerContainer = ((DefaultJmsListenerContainerFactory)
182+
jmsListenerContainerFactory).createListenerContainer(mock(JmsListenerEndpoint.class));
183+
assertTrue("wrong session transacted flag with no tx manager", listenerContainer.isSessionTransacted());
184+
assertNull(new DirectFieldAccessor(listenerContainer).getPropertyValue("transactionManager"));
185+
}
186+
140187
@Test
141188
public void testPubSubDisabledByDefault() {
142189
load(TestConfiguration.class);
@@ -350,6 +397,26 @@ JmsListenerContainerFactory<?> jmsListenerContainerFactory(
350397

351398
}
352399

400+
@Configuration
401+
protected static class TestConfiguration7 {
402+
403+
@Bean
404+
JtaTransactionManager transactionManager() {
405+
return mock(JtaTransactionManager.class);
406+
}
407+
408+
}
409+
410+
@Configuration
411+
protected static class TestConfiguration8 {
412+
413+
@Bean
414+
DataSourceTransactionManager transactionManager() {
415+
return mock(DataSourceTransactionManager.class);
416+
}
417+
418+
}
419+
353420
@Configuration
354421
@EnableJms
355422
protected static class EnableJmsConfiguration {

0 commit comments

Comments
 (0)