Skip to content

Commit a17bac5

Browse files
committed
Polish "Add support for configuring SimpleMessageListenerContainer"
See spring-projectsgh-47716
1 parent 2654900 commit a17bac5

File tree

4 files changed

+81
-43
lines changed

4 files changed

+81
-43
lines changed

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

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,28 @@
2424
import org.springframework.boot.context.properties.PropertyMapper;
2525
import org.springframework.boot.jms.autoconfigure.JmsProperties.Listener.Session;
2626
import org.springframework.jms.config.AbstractJmsListenerContainerFactory;
27+
import org.springframework.jms.config.JmsListenerContainerFactory;
2728
import org.springframework.jms.support.converter.MessageConverter;
2829
import org.springframework.jms.support.destination.DestinationResolver;
2930
import org.springframework.util.Assert;
3031

3132
/**
32-
* Configures {@link AbstractJmsListenerContainerFactory} with sensible defaults.
33+
* Configure common {@link JmsListenerContainerFactory} settings with sensible defaults.
34+
* <p>
35+
* This includes:
36+
* <li>A {@link DestinationResolver} is such a component is present.</li>
37+
* <li>A {@link MessageConverter} is such a component is present.</li>
38+
* <li>An {@link ExceptionListener} is such a component is present.</li>
39+
* <li>An {@link ObservationRegistry} is such a component is present.</li>
40+
* <li>Configuration properties of the {@code spring.jms} namespace that are common to all
41+
* implementations.</li>
3342
*
3443
* @param <T> the connection factory type.
44+
* @author Stephane Nicoll
45+
* @author Eddú Meléndez
3546
* @author Vedran Pavic
36-
* @since 4.0.0
47+
* @author Lasse Wulff
48+
* @since 4.1.0
3749
*/
3850
public abstract class AbstractJmsListenerContainerFactoryConfigurer<T extends AbstractJmsListenerContainerFactory<?>> {
3951

@@ -90,6 +102,15 @@ void setObservationRegistry(@Nullable ObservationRegistry observationRegistry) {
90102
this.observationRegistry = observationRegistry;
91103
}
92104

105+
/**
106+
* Return the {@link JmsProperties}.
107+
* @return the jms properties
108+
*/
109+
protected JmsProperties getJmsProperties() {
110+
Assert.state(this.jmsProperties != null, "'jmsProperties' must not be null");
111+
return this.jmsProperties;
112+
}
113+
93114
/**
94115
* Configure the specified jms listener container factory. The factory can be further
95116
* tuned and default settings can be overridden.
@@ -100,32 +121,21 @@ void setObservationRegistry(@Nullable ObservationRegistry observationRegistry) {
100121
public void configure(T factory, ConnectionFactory connectionFactory) {
101122
Assert.notNull(factory, "'factory' must not be null");
102123
Assert.notNull(connectionFactory, "'connectionFactory' must not be null");
103-
Assert.state(this.jmsProperties != null, "'jmsProperties' must not be null");
104-
JmsProperties.Listener listenerProperties = this.jmsProperties.getListener();
124+
JmsProperties properties = getJmsProperties();
125+
JmsProperties.Listener listenerProperties = properties.getListener();
105126
Session sessionProperties = listenerProperties.getSession();
106127
factory.setConnectionFactory(connectionFactory);
107128
PropertyMapper map = PropertyMapper.get();
108-
map.from(this.jmsProperties::isPubSubDomain).to(factory::setPubSubDomain);
109-
map.from(this.jmsProperties::isSubscriptionDurable).to(factory::setSubscriptionDurable);
110-
map.from(this.jmsProperties::getClientId).to(factory::setClientId);
129+
map.from(properties::isPubSubDomain).to(factory::setPubSubDomain);
130+
map.from(properties::isSubscriptionDurable).to(factory::setSubscriptionDurable);
131+
map.from(properties::getClientId).to(factory::setClientId);
111132
map.from(this.destinationResolver).to(factory::setDestinationResolver);
112133
map.from(this.messageConverter).to(factory::setMessageConverter);
113134
map.from(this.exceptionListener).to(factory::setExceptionListener);
114135
map.from(sessionProperties.getAcknowledgeMode()::getMode).to(factory::setSessionAcknowledgeMode);
115136
map.from(this.observationRegistry).to(factory::setObservationRegistry);
116137
map.from(sessionProperties::getTransacted).to(factory::setSessionTransacted);
117138
map.from(listenerProperties::isAutoStartup).to(factory::setAutoStartup);
118-
configure(factory, connectionFactory, this.jmsProperties);
119139
}
120140

121-
/**
122-
* Configures the given {@code factory} using the given {@code connectionFactory} and
123-
* {@code jmsProperties}.
124-
* @param factory the {@link AbstractJmsListenerContainerFactory} instance to
125-
* configure
126-
* @param connectionFactory the {@link ConnectionFactory} to use
127-
* @param jmsProperties the {@link JmsProperties} to use
128-
*/
129-
protected abstract void configure(T factory, ConnectionFactory connectionFactory, JmsProperties jmsProperties);
130-
131141
}

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
import org.springframework.transaction.jta.JtaTransactionManager;
2828

2929
/**
30-
* Configures {@link DefaultJmsListenerContainerFactory} with sensible defaults tuned
31-
* using configuration properties.
30+
* Configure {@link DefaultJmsListenerContainerFactory} with sensible defaults tuned using
31+
* configuration properties.
3232
* <p>
3333
* Can be injected into application code and used to define a custom
3434
* {@code DefaultJmsListenerContainerFactory} whose configuration is based upon that
@@ -39,6 +39,7 @@
3939
* @author Vedran Pavic
4040
* @author Lasse Wulff
4141
* @since 4.0.0
42+
* @see SimpleJmsListenerContainerFactoryConfigurer
4243
*/
4344
public final class DefaultJmsListenerContainerFactoryConfigurer
4445
extends AbstractJmsListenerContainerFactoryConfigurer<DefaultJmsListenerContainerFactory> {
@@ -55,10 +56,10 @@ void setTransactionManager(@Nullable JtaTransactionManager transactionManager) {
5556
}
5657

5758
@Override
58-
protected void configure(DefaultJmsListenerContainerFactory factory, ConnectionFactory connectionFactory,
59-
JmsProperties jmsProperties) {
59+
public void configure(DefaultJmsListenerContainerFactory factory, ConnectionFactory connectionFactory) {
60+
super.configure(factory, connectionFactory);
6061
PropertyMapper map = PropertyMapper.get();
61-
JmsProperties.Listener listenerProperties = jmsProperties.getListener();
62+
JmsProperties.Listener listenerProperties = getJmsProperties().getListener();
6263
Session sessionProperties = listenerProperties.getSession();
6364
map.from(this.transactionManager).to(factory::setTransactionManager);
6465
if (this.transactionManager == null && sessionProperties.getTransacted() == null) {

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

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,30 @@
1616

1717
package org.springframework.boot.jms.autoconfigure;
1818

19-
import jakarta.jms.ConnectionFactory;
20-
2119
import org.springframework.jms.config.SimpleJmsListenerContainerFactory;
20+
import org.springframework.jms.listener.DefaultMessageListenerContainer;
21+
import org.springframework.jms.listener.SimpleMessageListenerContainer;
2222

2323
/**
24-
* Configures {@link SimpleJmsListenerContainerFactory} with sensible defaults.
24+
* Configure {@link SimpleJmsListenerContainerFactory} with sensible defaults. In contrast
25+
* to {@link DefaultMessageListenerContainer} that uses a pull-based mechanism (polling)
26+
* to process messages, the {@link SimpleMessageListenerContainer} instances created by
27+
* this factory use a push-based mechanism that's very close to the spirit of the
28+
* standalone JMS specification.
29+
* <p>
30+
* As such, concurrency-related configuration properties from the {@code spring.jms}
31+
* namespace are not taken into account by this implementation.
32+
* <p>
33+
* Can be injected into application code and used to define a custom
34+
* {@code SimpleJmsListenerContainerFactory} whose configuration is based upon that
35+
* produced by auto-configuration.
2536
*
2637
* @author Vedran Pavic
38+
* @author Stephane Nicoll
2739
* @since 4.0.0
40+
* @see DefaultJmsListenerContainerFactoryConfigurer
2841
*/
2942
public final class SimpleJmsListenerContainerFactoryConfigurer
3043
extends AbstractJmsListenerContainerFactoryConfigurer<SimpleJmsListenerContainerFactory> {
3144

32-
@Override
33-
protected void configure(SimpleJmsListenerContainerFactory factory, ConnectionFactory connectionFactory,
34-
JmsProperties jmsProperties) {
35-
}
36-
3745
}

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

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.springframework.jms.core.JmsMessagingTemplate;
4646
import org.springframework.jms.core.JmsTemplate;
4747
import org.springframework.jms.listener.DefaultMessageListenerContainer;
48+
import org.springframework.jms.listener.SimpleMessageListenerContainer;
4849
import org.springframework.jms.support.converter.MessageConverter;
4950
import org.springframework.jms.support.destination.DestinationResolver;
5051
import org.springframework.transaction.jta.JtaTransactionManager;
@@ -168,20 +169,38 @@ void testJmsListenerContainerFactoryWithCustomSettings() {
168169
"spring.jms.listener.receiveTimeout=2s", "spring.jms.listener.maxConcurrency=10",
169170
"spring.jms.subscription-durable=true", "spring.jms.client-id=exampleId",
170171
"spring.jms.listener.max-messages-per-task=5")
171-
.run(this::testJmsListenerContainerFactoryWithCustomSettings);
172+
.run((context) -> {
173+
DefaultMessageListenerContainer container = getContainer(context, "jmsListenerContainerFactory");
174+
assertThat(container.isAutoStartup()).isFalse();
175+
assertThat(container.getSessionAcknowledgeMode()).isEqualTo(Session.CLIENT_ACKNOWLEDGE);
176+
assertThat(container.isSessionTransacted()).isFalse();
177+
assertThat(container.getConcurrentConsumers()).isEqualTo(2);
178+
assertThat(container.getMaxConcurrentConsumers()).isEqualTo(10);
179+
assertThat(container).hasFieldOrPropertyWithValue("receiveTimeout", 2000L);
180+
assertThat(container).hasFieldOrPropertyWithValue("maxMessagesPerTask", 5);
181+
assertThat(container.isSubscriptionDurable()).isTrue();
182+
assertThat(container.getClientId()).isEqualTo("exampleId");
183+
});
172184
}
173185

174-
private void testJmsListenerContainerFactoryWithCustomSettings(AssertableApplicationContext loaded) {
175-
DefaultMessageListenerContainer container = getContainer(loaded, "jmsListenerContainerFactory");
176-
assertThat(container.isAutoStartup()).isFalse();
177-
assertThat(container.getSessionAcknowledgeMode()).isEqualTo(Session.CLIENT_ACKNOWLEDGE);
178-
assertThat(container.isSessionTransacted()).isFalse();
179-
assertThat(container.getConcurrentConsumers()).isEqualTo(2);
180-
assertThat(container.getMaxConcurrentConsumers()).isEqualTo(10);
181-
assertThat(container).hasFieldOrPropertyWithValue("receiveTimeout", 2000L);
182-
assertThat(container).hasFieldOrPropertyWithValue("maxMessagesPerTask", 5);
183-
assertThat(container.isSubscriptionDurable()).isTrue();
184-
assertThat(container.getClientId()).isEqualTo("exampleId");
186+
@Test
187+
void testManualJmsListenerContainerFactoryWithCustomSettings() {
188+
this.contextRunner.withUserConfiguration(TestConfiguration6.class, EnableJmsConfiguration.class)
189+
.withPropertyValues("spring.jms.listener.autoStartup=false",
190+
"spring.jms.listener.session.acknowledgeMode=client",
191+
"spring.jms.listener.session.transacted=false", "spring.jms.subscription-durable=true",
192+
"spring.jms.client-id=exampleId")
193+
.run((context) -> {
194+
SimpleJmsListenerContainerFactory containerFactory = context.getBean("jmsListenerContainerFactory",
195+
SimpleJmsListenerContainerFactory.class);
196+
SimpleMessageListenerContainer container = containerFactory
197+
.createListenerContainer(mock(JmsListenerEndpoint.class));
198+
assertThat(container.isAutoStartup()).isFalse();
199+
assertThat(container.getSessionAcknowledgeMode()).isEqualTo(Session.CLIENT_ACKNOWLEDGE);
200+
assertThat(container.isSessionTransacted()).isFalse();
201+
assertThat(container.isSubscriptionDurable()).isTrue();
202+
assertThat(container.getClientId()).isEqualTo("exampleId");
203+
});
185204
}
186205

187206
@Test

0 commit comments

Comments
 (0)