Skip to content

Commit 626065a

Browse files
committed
Add support for JmsClient
This commits adds auto-configuration for the new JmsClient API introduced in Spring Framework 7. JmsClient is auto-configured the same way as JmsTemplate and uses it behind the scenes. Closes gh-46293
1 parent 870e652 commit 626065a

File tree

14 files changed

+178
-118
lines changed

14 files changed

+178
-118
lines changed

spring-boot-project/spring-boot-activemq/src/dockerTest/java/org/springframework/boot/activemq/testcontainers/ActiveMQClassicContainerConnectionDetailsFactoryIntegrationTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
import org.springframework.context.annotation.Bean;
3636
import org.springframework.context.annotation.Configuration;
3737
import org.springframework.jms.annotation.JmsListener;
38-
import org.springframework.jms.core.JmsMessagingTemplate;
38+
import org.springframework.jms.core.JmsClient;
3939
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
4040

4141
import static org.assertj.core.api.Assertions.assertThat;
@@ -54,14 +54,14 @@ class ActiveMQClassicContainerConnectionDetailsFactoryIntegrationTests {
5454
static final ActiveMQContainer activemq = TestImage.container(ActiveMQContainer.class);
5555

5656
@Autowired
57-
private JmsMessagingTemplate jmsTemplate;
57+
private JmsClient jmsClient;
5858

5959
@Autowired
6060
private TestListener listener;
6161

6262
@Test
6363
void connectionCanBeMadeToActiveMQContainer() {
64-
this.jmsTemplate.convertAndSend("sample.queue", "message");
64+
this.jmsClient.destination("sample.queue").send("message");
6565
Awaitility.waitAtMost(Duration.ofMinutes(1))
6666
.untilAsserted(() -> assertThat(this.listener.messages).containsExactly("message"));
6767
}

spring-boot-project/spring-boot-activemq/src/dockerTest/java/org/springframework/boot/activemq/testcontainers/ActiveMQContainerConnectionDetailsFactoryIntegrationTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
import org.springframework.context.annotation.Bean;
3636
import org.springframework.context.annotation.Configuration;
3737
import org.springframework.jms.annotation.JmsListener;
38-
import org.springframework.jms.core.JmsMessagingTemplate;
38+
import org.springframework.jms.core.JmsClient;
3939
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
4040

4141
import static org.assertj.core.api.Assertions.assertThat;
@@ -54,14 +54,14 @@ class ActiveMQContainerConnectionDetailsFactoryIntegrationTests {
5454
static final SymptomaActiveMQContainer activemq = TestImage.container(SymptomaActiveMQContainer.class);
5555

5656
@Autowired
57-
private JmsMessagingTemplate jmsTemplate;
57+
private JmsClient jmsClient;
5858

5959
@Autowired
6060
private TestListener listener;
6161

6262
@Test
6363
void connectionCanBeMadeToActiveMQContainer() {
64-
this.jmsTemplate.convertAndSend("sample.queue", "message");
64+
this.jmsClient.destination("sample.queue").send("message");
6565
Awaitility.waitAtMost(Duration.ofMinutes(1))
6666
.untilAsserted(() -> assertThat(this.listener.messages).containsExactly("message"));
6767
}

spring-boot-project/spring-boot-artemis/src/dockerTest/java/org/springframework/boot/artemis/testcontainers/ArtemisContainerConnectionDetailsFactoryIntegrationTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
import org.springframework.context.annotation.Bean;
3636
import org.springframework.context.annotation.Configuration;
3737
import org.springframework.jms.annotation.JmsListener;
38-
import org.springframework.jms.core.JmsMessagingTemplate;
38+
import org.springframework.jms.core.JmsClient;
3939
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
4040

4141
import static org.assertj.core.api.Assertions.assertThat;
@@ -54,14 +54,14 @@ class ArtemisContainerConnectionDetailsFactoryIntegrationTests {
5454
static final ArtemisContainer artemis = TestImage.container(ArtemisContainer.class);
5555

5656
@Autowired
57-
private JmsMessagingTemplate jmsTemplate;
57+
private JmsClient jmsClient;
5858

5959
@Autowired
6060
private TestListener listener;
6161

6262
@Test
6363
void connectionCanBeMadeToActiveMQContainer() {
64-
this.jmsTemplate.convertAndSend("sample.queue", "message");
64+
this.jmsClient.destination("sample.queue").send("message");
6565
Awaitility.waitAtMost(Duration.ofMinutes(1))
6666
.untilAsserted(() -> assertThat(this.listener.messages).containsExactly("message"));
6767
}

spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/metrics.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@ Auto-configuration enables the instrumentation of all available javadoc:org.spri
725725
This will produce `"jms.message.publish"` and `"jms.message.process"` metrics respectively.
726726
See the {url-spring-framework-docs}/integration/observability.html#observability.jms[Spring Framework reference documentation for more information on produced observations].
727727

728+
NOTE: javadoc:org.springframework.jms.core.JmsClient[] and javadoc:org.springframework.jms.core.JmsMessagingTemplate[] that uses a javadoc:org.springframework.jms.core.JmsTemplate[] bean are also instrumented.
728729

729730

730731
[[actuator.metrics.supported.spring-mvc]]

spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/index.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[[messaging]]
22
= Messaging
33

4-
The Spring Framework provides extensive support for integrating with messaging systems, from simplified use of the JMS API using javadoc:org.springframework.jms.core.JmsTemplate[] to a complete infrastructure to receive messages asynchronously.
4+
The Spring Framework provides extensive support for integrating with messaging systems, from simplified use of the JMS API using javadoc:org.springframework.jms.core.JmsClient[] to a complete infrastructure to receive messages asynchronously.
55
Spring AMQP provides a similar feature set for the Advanced Message Queuing Protocol.
66
Spring Boot also provides auto-configuration options for javadoc:org.springframework.amqp.rabbit.core.RabbitTemplate[] and RabbitMQ.
77
Spring WebSocket natively includes support for STOMP messaging, and Spring Boot has support for that through starters and a small amount of auto-configuration.

spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/jms.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,11 @@ spring:
145145
[[messaging.jms.sending]]
146146
== Sending a Message
147147

148-
Spring's javadoc:org.springframework.jms.core.JmsTemplate[] is auto-configured, and you can autowire it directly into your own beans, as shown in the following example:
148+
Spring's javadoc:org.springframework.jms.core.JmsClient[] is auto-configured, and you can autowire it directly into your own beans, as shown in the following example:
149149

150150
include-code::MyBean[]
151151

152-
NOTE: javadoc:org.springframework.jms.core.JmsMessagingTemplate[] can be injected in a similar manner.
152+
NOTE: javadoc:org.springframework.jms.core.JmsMessagingTemplate[] can be injected in a similar manner, and both use the traditional javadoc:org.springframework.jms.core.JmsTemplate[] that can be injected as well.
153153
If a javadoc:org.springframework.jms.support.destination.DestinationResolver[] or a javadoc:org.springframework.jms.support.converter.MessageConverter[] bean is defined, it is associated automatically to the auto-configured javadoc:org.springframework.jms.core.JmsTemplate[].
154154

155155

spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/jms/sending/MyBean.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,21 @@
1616

1717
package org.springframework.boot.docs.messaging.jms.sending;
1818

19-
import org.springframework.jms.core.JmsTemplate;
19+
import org.springframework.jms.core.JmsClient;
2020
import org.springframework.stereotype.Component;
2121

2222
@Component
2323
public class MyBean {
2424

25-
private final JmsTemplate jmsTemplate;
25+
private final JmsClient jmsClient;
2626

27-
public MyBean(JmsTemplate jmsTemplate) {
28-
this.jmsTemplate = jmsTemplate;
27+
public MyBean(JmsClient jmsClient) {
28+
this.jmsClient = jmsClient;
2929
}
3030

3131
// @fold:on // ...
3232
public void someMethod() {
33-
this.jmsTemplate.convertAndSend("hello");
33+
this.jmsClient.destination("myQueue").send("hello");
3434
}
3535
// @fold:off
3636

spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/jms/sending/MyBean.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616

1717
package org.springframework.boot.docs.messaging.jms.sending
1818

19-
import org.springframework.jms.core.JmsTemplate
19+
import org.springframework.jms.core.JmsClient
2020
import org.springframework.stereotype.Component
2121

2222
@Component
23-
class MyBean(private val jmsTemplate: JmsTemplate) {
23+
class MyBean(private val jmsClient: JmsClient) {
2424

2525
// @fold:on // ...
2626
fun someMethod() {
27-
jmsTemplate.convertAndSend("hello")
27+
jmsClient.destination("myQueue").send("hello")
2828
}
2929
// @fold:off
3030

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

Lines changed: 3 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,24 @@
1616

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

19-
import java.time.Duration;
2019
import java.util.List;
2120

22-
import io.micrometer.observation.ObservationRegistry;
2321
import jakarta.jms.ConnectionFactory;
2422
import jakarta.jms.Message;
2523

2624
import org.springframework.aot.hint.ExecutableMode;
2725
import org.springframework.aot.hint.RuntimeHints;
2826
import org.springframework.aot.hint.RuntimeHintsRegistrar;
2927
import org.springframework.aot.hint.TypeReference;
30-
import org.springframework.beans.factory.ObjectProvider;
3128
import org.springframework.boot.autoconfigure.AutoConfiguration;
3229
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
3330
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
3431
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
35-
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
36-
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
3732
import org.springframework.boot.context.properties.EnableConfigurationProperties;
38-
import org.springframework.boot.context.properties.PropertyMapper;
3933
import org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration.JmsRuntimeHints;
40-
import org.springframework.boot.jms.autoconfigure.JmsProperties.DeliveryMode;
41-
import org.springframework.boot.jms.autoconfigure.JmsProperties.Template;
42-
import org.springframework.context.annotation.Bean;
43-
import org.springframework.context.annotation.Configuration;
4434
import org.springframework.context.annotation.Import;
4535
import org.springframework.context.annotation.ImportRuntimeHints;
46-
import org.springframework.jms.core.JmsMessageOperations;
47-
import org.springframework.jms.core.JmsMessagingTemplate;
48-
import org.springframework.jms.core.JmsOperations;
4936
import org.springframework.jms.core.JmsTemplate;
50-
import org.springframework.jms.support.converter.MessageConverter;
51-
import org.springframework.jms.support.destination.DestinationResolver;
5237

5338
/**
5439
* {@link EnableAutoConfiguration Auto-configuration} for Spring JMS.
@@ -62,81 +47,12 @@
6247
@ConditionalOnClass({ Message.class, JmsTemplate.class })
6348
@ConditionalOnBean(ConnectionFactory.class)
6449
@EnableConfigurationProperties(JmsProperties.class)
65-
@Import(JmsAnnotationDrivenConfiguration.class)
50+
@Import({ JmsClientConfigurations.JmsTemplateConfiguration.class,
51+
JmsClientConfigurations.MessagingTemplateConfiguration.class,
52+
JmsClientConfigurations.JmsClientConfiguration.class, JmsAnnotationDrivenConfiguration.class })
6653
@ImportRuntimeHints(JmsRuntimeHints.class)
6754
public class JmsAutoConfiguration {
6855

69-
@Configuration(proxyBeanMethods = false)
70-
protected static class JmsTemplateConfiguration {
71-
72-
private final JmsProperties properties;
73-
74-
private final ObjectProvider<DestinationResolver> destinationResolver;
75-
76-
private final ObjectProvider<MessageConverter> messageConverter;
77-
78-
private final ObjectProvider<ObservationRegistry> observationRegistry;
79-
80-
public JmsTemplateConfiguration(JmsProperties properties,
81-
ObjectProvider<DestinationResolver> destinationResolver,
82-
ObjectProvider<MessageConverter> messageConverter,
83-
ObjectProvider<ObservationRegistry> observationRegistry) {
84-
this.properties = properties;
85-
this.destinationResolver = destinationResolver;
86-
this.messageConverter = messageConverter;
87-
this.observationRegistry = observationRegistry;
88-
}
89-
90-
@Bean
91-
@ConditionalOnMissingBean(JmsOperations.class)
92-
@ConditionalOnSingleCandidate(ConnectionFactory.class)
93-
public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {
94-
PropertyMapper map = PropertyMapper.get();
95-
JmsTemplate template = new JmsTemplate(connectionFactory);
96-
template.setPubSubDomain(this.properties.isPubSubDomain());
97-
map.from(this.destinationResolver::getIfUnique).whenNonNull().to(template::setDestinationResolver);
98-
map.from(this.messageConverter::getIfUnique).whenNonNull().to(template::setMessageConverter);
99-
map.from(this.observationRegistry::getIfUnique).whenNonNull().to(template::setObservationRegistry);
100-
mapTemplateProperties(this.properties.getTemplate(), template);
101-
return template;
102-
}
103-
104-
private void mapTemplateProperties(Template properties, JmsTemplate template) {
105-
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
106-
map.from(properties.getSession().getAcknowledgeMode()::getMode).to(template::setSessionAcknowledgeMode);
107-
map.from(properties.getSession()::isTransacted).to(template::setSessionTransacted);
108-
map.from(properties::getDefaultDestination).whenNonNull().to(template::setDefaultDestinationName);
109-
map.from(properties::getDeliveryDelay).whenNonNull().as(Duration::toMillis).to(template::setDeliveryDelay);
110-
map.from(properties::determineQosEnabled).to(template::setExplicitQosEnabled);
111-
map.from(properties::getDeliveryMode).as(DeliveryMode::getValue).to(template::setDeliveryMode);
112-
map.from(properties::getPriority).whenNonNull().to(template::setPriority);
113-
map.from(properties::getTimeToLive).whenNonNull().as(Duration::toMillis).to(template::setTimeToLive);
114-
map.from(properties::getReceiveTimeout).as(Duration::toMillis).to(template::setReceiveTimeout);
115-
}
116-
117-
}
118-
119-
@Configuration(proxyBeanMethods = false)
120-
@ConditionalOnClass(JmsMessagingTemplate.class)
121-
@Import(JmsTemplateConfiguration.class)
122-
protected static class MessagingTemplateConfiguration {
123-
124-
@Bean
125-
@ConditionalOnMissingBean(JmsMessageOperations.class)
126-
@ConditionalOnSingleCandidate(JmsTemplate.class)
127-
public JmsMessagingTemplate jmsMessagingTemplate(JmsProperties properties, JmsTemplate jmsTemplate) {
128-
JmsMessagingTemplate messagingTemplate = new JmsMessagingTemplate(jmsTemplate);
129-
mapTemplateProperties(properties.getTemplate(), messagingTemplate);
130-
return messagingTemplate;
131-
}
132-
133-
private void mapTemplateProperties(Template properties, JmsMessagingTemplate messagingTemplate) {
134-
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
135-
map.from(properties::getDefaultDestination).to(messagingTemplate::setDefaultDestinationName);
136-
}
137-
138-
}
139-
14056
static class JmsRuntimeHints implements RuntimeHintsRegistrar {
14157

14258
@Override

0 commit comments

Comments
 (0)