Skip to content

Commit 5f6e89e

Browse files
committed
Add support for configuring JMS listener sessionTransacted
This commit introduces `spring.jms.listener.session-transacted` property in order to enable explicit configuration of `sessionTransacted` on the `DefaultMessageListenerContainer`. Prior to this commit, `sessionTransacted` would be configured implicitly based on presence of `JtaTransactionManager`. Closes gh-37472
1 parent 83666d4 commit 5f6e89e

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
3232
*
3333
* @author Stephane Nicoll
3434
* @author Eddú Meléndez
35+
* @author Vedran Pavic
3536
* @since 1.3.3
3637
*/
3738
public final class DefaultJmsListenerContainerFactoryConfigurer {
@@ -101,12 +102,16 @@ public void configure(DefaultJmsListenerContainerFactory factory, ConnectionFact
101102
Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
102103
factory.setConnectionFactory(connectionFactory);
103104
factory.setPubSubDomain(this.jmsProperties.isPubSubDomain());
105+
JmsProperties.Listener listener = this.jmsProperties.getListener();
104106
if (this.transactionManager != null) {
105107
factory.setTransactionManager(this.transactionManager);
106108
}
107-
else {
109+
else if (listener.getSessionTransacted() == null) {
108110
factory.setSessionTransacted(true);
109111
}
112+
if (listener.getSessionTransacted() != null) {
113+
factory.setSessionTransacted(listener.getSessionTransacted());
114+
}
110115
if (this.destinationResolver != null) {
111116
factory.setDestinationResolver(this.destinationResolver);
112117
}
@@ -116,7 +121,6 @@ public void configure(DefaultJmsListenerContainerFactory factory, ConnectionFact
116121
if (this.exceptionListener != null) {
117122
factory.setExceptionListener(this.exceptionListener);
118123
}
119-
JmsProperties.Listener listener = this.jmsProperties.getListener();
120124
factory.setAutoStartup(listener.isAutoStartup());
121125
if (listener.getAcknowledgeMode() != null) {
122126
factory.setSessionAcknowledgeMode(listener.getAcknowledgeMode().getMode());

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
* @author Greg Turnquist
2727
* @author Phillip Webb
2828
* @author Stephane Nicoll
29+
* @author Vedran Pavic
2930
* @since 1.0.0
3031
*/
3132
@ConfigurationProperties(prefix = "spring.jms")
@@ -145,6 +146,11 @@ public static class Listener {
145146
*/
146147
private AcknowledgeMode acknowledgeMode;
147148

149+
/**
150+
* Whether the container should use transacted JMS sessions.
151+
*/
152+
private Boolean sessionTransacted;
153+
148154
/**
149155
* Minimum number of concurrent consumers.
150156
*/
@@ -178,6 +184,14 @@ public void setAcknowledgeMode(AcknowledgeMode acknowledgeMode) {
178184
this.acknowledgeMode = acknowledgeMode;
179185
}
180186

187+
public Boolean getSessionTransacted() {
188+
return this.sessionTransacted;
189+
}
190+
191+
public void setSessionTransacted(Boolean sessionTransacted) {
192+
this.sessionTransacted = sessionTransacted;
193+
}
194+
181195
public Integer getConcurrency() {
182196
return this.concurrency;
183197
}

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
* @author Stephane Nicoll
5858
* @author Aurélien Leboulanger
5959
* @author Eddú Meléndez
60+
* @author Vedran Pavic
6061
*/
6162
class JmsAutoConfigurationTests {
6263

@@ -143,15 +144,16 @@ void jmsListenerContainerFactoryWhenMultipleConnectionFactoryBeansShouldBackOff(
143144
void testJmsListenerContainerFactoryWithCustomSettings() {
144145
this.contextRunner.withUserConfiguration(EnableJmsConfiguration.class)
145146
.withPropertyValues("spring.jms.listener.autoStartup=false", "spring.jms.listener.acknowledgeMode=client",
146-
"spring.jms.listener.concurrency=2", "spring.jms.listener.receiveTimeout=2s",
147-
"spring.jms.listener.maxConcurrency=10")
147+
"spring.jms.listener.sessionTransacted=false", "spring.jms.listener.concurrency=2",
148+
"spring.jms.listener.receiveTimeout=2s", "spring.jms.listener.maxConcurrency=10")
148149
.run(this::testJmsListenerContainerFactoryWithCustomSettings);
149150
}
150151

151152
private void testJmsListenerContainerFactoryWithCustomSettings(AssertableApplicationContext loaded) {
152153
DefaultMessageListenerContainer container = getContainer(loaded, "jmsListenerContainerFactory");
153154
assertThat(container.isAutoStartup()).isFalse();
154155
assertThat(container.getSessionAcknowledgeMode()).isEqualTo(Session.CLIENT_ACKNOWLEDGE);
156+
assertThat(container.isSessionTransacted()).isFalse();
155157
assertThat(container.getConcurrentConsumers()).isEqualTo(2);
156158
assertThat(container.getMaxConcurrentConsumers()).isEqualTo(10);
157159
assertThat(container).hasFieldOrPropertyWithValue("receiveTimeout", 2000L);
@@ -179,6 +181,18 @@ void testDefaultContainerFactoryWithJtaTransactionManager() {
179181
});
180182
}
181183

184+
@Test
185+
void testDefaultContainerFactoryWithJtaTransactionManagerAndSessionTransactedEnabled() {
186+
this.contextRunner.withUserConfiguration(TestConfiguration7.class, EnableJmsConfiguration.class)
187+
.withPropertyValues("spring.jms.listener.sessionTransacted=true")
188+
.run((context) -> {
189+
DefaultMessageListenerContainer container = getContainer(context, "jmsListenerContainerFactory");
190+
assertThat(container.isSessionTransacted()).isTrue();
191+
assertThat(container).hasFieldOrPropertyWithValue("transactionManager",
192+
context.getBean(JtaTransactionManager.class));
193+
});
194+
}
195+
182196
@Test
183197
void testDefaultContainerFactoryNonJtaTransactionManager() {
184198
this.contextRunner.withUserConfiguration(TestConfiguration8.class, EnableJmsConfiguration.class)
@@ -198,6 +212,17 @@ void testDefaultContainerFactoryNoTransactionManager() {
198212
});
199213
}
200214

215+
@Test
216+
void testDefaultContainerFactoryNoTransactionManagerAndSessionTransactedDisabled() {
217+
this.contextRunner.withUserConfiguration(EnableJmsConfiguration.class)
218+
.withPropertyValues("spring.jms.listener.sessionTransacted=false")
219+
.run((context) -> {
220+
DefaultMessageListenerContainer container = getContainer(context, "jmsListenerContainerFactory");
221+
assertThat(container.isSessionTransacted()).isFalse();
222+
assertThat(container).hasFieldOrPropertyWithValue("transactionManager", null);
223+
});
224+
}
225+
201226
@Test
202227
void testDefaultContainerFactoryWithMessageConverters() {
203228
this.contextRunner.withUserConfiguration(MessageConvertersConfiguration.class, EnableJmsConfiguration.class)

0 commit comments

Comments
 (0)