Skip to content

Commit b5ba1ec

Browse files
committed
Add AMQP 1.0 generic auto-configuration
This commit adds auto-configuration for the generic AMQP 1.0 client in Spring AMQP 4.1, using Qpid ProtonJ. Support for connection factory, client and listener endpoints are available. The "spring.amqp" namespace exposes settings to connect to an AMQP 1.0 compliant broker and customize client and listeners settings. Docker compose and testcontainers support using RabbitMQ, ActiveMQ, and Artemis have been added too. Closes gh-49678
1 parent f48cc3a commit b5ba1ec

79 files changed

Lines changed: 3387 additions & 31 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ private void dataMigrationPrefixes(Config prefix) {
171171

172172
private void integrationPrefixes(Config prefix) {
173173
prefix.accept("spring.activemq");
174+
prefix.accept("spring.amqp");
174175
prefix.accept("spring.artemis");
175176
prefix.accept("spring.batch");
176177
prefix.accept("spring.integration");

documentation/spring-boot-docs/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ dependencies {
9494
implementation(project(path: ":loader:spring-boot-loader-tools"))
9595
implementation(project(path: ":module:spring-boot-actuator"))
9696
implementation(project(path: ":module:spring-boot-actuator-autoconfigure"))
97+
implementation(project(path: ":module:spring-boot-amqp"))
9798
implementation(project(path: ":module:spring-boot-cache"))
9899
implementation(project(path: ":module:spring-boot-cache-test"))
99100
implementation(project(path: ":module:spring-boot-data-cassandra"))

documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1716,13 +1716,13 @@
17161716
* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#features.messaging.amqp.rabbit]
17171717
* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#messaging.amqp.rabbit]
17181718
* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#messaging.amqp.rabbitmq]
1719-
* xref:reference:messaging/amqp.adoc#messaging.amqp.receiving[#boot-features-using-amqp-receiving]
1720-
* xref:reference:messaging/amqp.adoc#messaging.amqp.receiving[#features.messaging.amqp.receiving]
1721-
* xref:reference:messaging/amqp.adoc#messaging.amqp.receiving[#messaging.amqp.receiving]
1722-
* xref:reference:messaging/amqp.adoc#messaging.amqp.sending-stream[#messaging.amqp.sending-stream]
1723-
* xref:reference:messaging/amqp.adoc#messaging.amqp.sending[#boot-features-using-amqp-sending]
1724-
* xref:reference:messaging/amqp.adoc#messaging.amqp.sending[#features.messaging.amqp.sending]
1725-
* xref:reference:messaging/amqp.adoc#messaging.amqp.sending[#messaging.amqp.sending]
1719+
* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq.receiving[#boot-features-using-amqp-receiving]
1720+
* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq.receiving[#features.messaging.amqp.receiving]
1721+
* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq.receiving[#messaging.amqp.receiving]
1722+
* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq.sending-stream[#messaging.amqp.sending-stream]
1723+
* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq.sending[#boot-features-using-amqp-sending]
1724+
* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq.sending[#features.messaging.amqp.sending]
1725+
* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq.sending[#messaging.amqp.sending]
17261726
* xref:reference:messaging/amqp.adoc#messaging.amqp[#boot-features-amqp]
17271727
* xref:reference:messaging/amqp.adoc#messaging.amqp[#features.messaging.amqp]
17281728
* xref:reference:messaging/amqp.adoc#messaging.amqp[#messaging.amqp]

documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ The following service connections are currently supported:
8686
| javadoc:org.springframework.boot.activemq.autoconfigure.ActiveMQConnectionDetails[]
8787
| Containers named "symptoma/activemq", "apache/activemq-classic" or "apache/activemq"
8888

89+
| javadoc:org.springframework.boot.amqp.autoconfigure.AmqpConnectionDetails[]
90+
| Containers named "rabbitmq" or "apache/activemq-classic" or "apache/activemq-artemis"
91+
8992
| javadoc:org.springframework.boot.artemis.autoconfigure.ArtemisConnectionDetails[]
9093
| Containers named "apache/activemq-artemis" or "apache/artemis"
9194

documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/amqp.adoc

Lines changed: 80 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,78 @@
33

44
The Advanced Message Queuing Protocol (AMQP) is a platform-neutral, wire-level protocol for message-oriented middleware.
55
The Spring AMQP project applies core Spring concepts to the development of AMQP-based messaging solutions.
6-
Spring Boot offers several conveniences for working with AMQP through RabbitMQ, including the `spring-boot-starter-rabbitmq` starter.
6+
Spring Boot offers several conveniences for working with AMQP: generic AMQP 1.0 support is provided by the `spring-boot-starter-amqp` starter while specific RabbitMQ support is available via the `spring-boot-starter-rabbitmq` starter.
7+
8+
9+
10+
[[messaging.amqp.generic]]
11+
== Generic AMQP 1.0 Support
12+
13+
AMQP 1.0 is supported by several brokers and messaging services beyond RabbitMQ, including ActiveMQ, Azure Service Bus, and others.
14+
Spring AMQP provides {url-spring-amqp-docs}/amqp10-client.html[generic support for AMQP 1.0] via `org.springframework.amqp:spring-amqp-client` that is based on the https://github.com/apache/qpid-protonj2/blob/main/protonj2-client/README.md[Qpid ProtonJ2 Client Library].
15+
16+
AMQP configuration is controlled by external configuration properties in `+spring.amqp.*+`.
17+
For example, you might declare the following in your configuration:
18+
19+
[configprops,yaml]
20+
----
21+
spring:
22+
amqp:
23+
host: "localhost"
24+
port: 5672
25+
username: "admin"
26+
password: "secret"
27+
----
28+
29+
To configure javadoc:org.apache.qpid.protonj2.client.ConnectionOptions[connection options] of the auto-configured javadoc:org.springframework.amqp.client.AmqpConnectionFactory[], define a javadoc:org.springframework.boot.amqp.autoconfigure.ConnectionOptionsCustomizer[] bean.
30+
31+
[[messaging.amqp.generic.sending]]
32+
=== Sending a Message
33+
34+
Spring's javadoc:org.springframework.amqp.client.AmqpClient[] is auto-configured, and you can autowire it directly into your own beans, as shown in the following example:
35+
36+
include-code::MyBean[]
37+
38+
If a javadoc:org.springframework.amqp.support.converter.MessageConverter[] bean is defined, it is associated automatically with the auto-configured javadoc:org.springframework.amqp.client.AmqpClient[].
39+
If no such converter is defined and Jackson is available, javadoc:org.springframework.amqp.support.converter.JacksonJsonMessageConverter[] is used.
40+
41+
Client-specific settings can be configured as follows:
42+
43+
[configprops,yaml]
44+
----
45+
spring:
46+
amqp:
47+
client:
48+
default-to-address: "/queues/default_queue"
49+
completion-timeout: "500ms"
50+
----
51+
52+
To further configure the auto-configured javadoc:org.springframework.amqp.client.AmqpClient[], define a javadoc:org.springframework.boot.amqp.autoconfigure.AmqpClientCustomizer[] bean.
53+
54+
55+
56+
[[messaging.amqp.generic.receiving]]
57+
=== Receiving a Message
58+
59+
When the generic AMQP 1.0 infrastructure is present, any bean can be annotated with javadoc:org.springframework.amqp.client.annotation.AmqpListener[format=annotation] to create a listener endpoint.
60+
If no javadoc:org.springframework.amqp.client.config.MethodAmqpMessageListenerContainerFactory[] has been defined, a default one is automatically configured.
61+
If a javadoc:org.springframework.amqp.support.converter.MessageConverter[] or a javadoc:org.springframework.amqp.client.listener.AmqpListenerErrorHandler[] bean is defined, it is automatically associated with the default factory.
62+
63+
The following sample component creates a listener endpoint on the `/queues/someQueue` address:
64+
65+
include-code::MyBean[]
66+
67+
TIP: See javadoc:org.springframework.amqp.client.config.EnableAmqp[format=annotation] for more details.
68+
69+
If you need to create more javadoc:org.springframework.amqp.client.config.MethodAmqpMessageListenerContainerFactory[] instances or if you want to override the default, Spring Boot provides a javadoc:org.springframework.boot.amqp.autoconfigure.AmqpMessageListenerContainerFactoryConfigurer[] that you can use to initialize a javadoc:org.springframework.amqp.client.config.MethodAmqpMessageListenerContainerFactory[] with the same settings as the factory used by the auto-configuration.
70+
71+
For instance, the following configuration class exposes another factory that uses a specific javadoc:org.springframework.amqp.support.converter.MessageConverter[]:
72+
73+
include-code::custom/MyAmqpConfiguration[]
74+
75+
Then you can use the factory in any javadoc:org.springframework.amqp.client.annotation.AmqpListener[format=annotation]-annotated method, as follows:
76+
77+
include-code::custom/MyBean[]
778

879

980

@@ -49,8 +120,8 @@ TIP: See https://spring.io/blog/2010/06/14/understanding-amqp-the-protocol-used-
49120

50121

51122

52-
[[messaging.amqp.sending]]
53-
== Sending a Message
123+
[[messaging.amqp.rabbitmq.sending]]
124+
=== Sending a Message
54125

55126
Spring's javadoc:org.springframework.amqp.core.AmqpTemplate[] and javadoc:org.springframework.amqp.core.AmqpAdmin[] are auto-configured, and you can autowire them directly into your own beans, as shown in the following example:
56127

@@ -82,8 +153,8 @@ If there's a bean of type javadoc:org.springframework.amqp.rabbit.support.microm
82153

83154

84155

85-
[[messaging.amqp.sending-stream]]
86-
== Sending a Message To A Stream
156+
[[messaging.amqp.rabbitmq.sending-stream]]
157+
=== Sending a Message To A Stream
87158

88159
To send a message to a particular stream, specify the name of the stream, as shown in the following example:
89160

@@ -101,14 +172,14 @@ If you need to create more javadoc:org.springframework.rabbit.stream.producer.Ra
101172

102173

103174

104-
[[messaging.amqp.sending-stream.ssl]]
105-
=== SSL
175+
[[messaging.amqp.rabbitmq.sending-stream.ssl]]
176+
==== SSL
106177
To use SSL with RabbitMQ Streams, set configprop:spring.rabbitmq.stream.ssl.enabled[] to `true` or set configprop:spring.rabbitmq.stream.ssl.bundle[] to configure the xref:features/ssl.adoc#features.ssl.bundles[SSL bundle] to use.
107178

108179

109180

110-
[[messaging.amqp.receiving]]
111-
== Receiving a Message
181+
[[messaging.amqp.rabbitmq.receiving]]
182+
=== Receiving a Message
112183

113184
When the Rabbit infrastructure is present, any bean can be annotated with javadoc:org.springframework.amqp.rabbit.annotation.RabbitListener[format=annotation] to create a listener endpoint.
114185
If no javadoc:org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory[] has been defined, a default javadoc:org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory[] is automatically configured and you can switch to a direct container using the configprop:spring.rabbitmq.listener.type[] property.

documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ The following service connection factories are provided in the `spring-boot-test
128128
| javadoc:org.springframework.boot.activemq.autoconfigure.ActiveMQConnectionDetails[]
129129
| Containers named "symptoma/activemq" or javadoc:org.testcontainers.activemq.ActiveMQContainer[]
130130

131+
| javadoc:org.springframework.boot.amqp.autoconfigure.AmqpConnectionDetails[]
132+
| Containers of types javadoc:{url-testcontainers-rabbitmq-javadoc}/org.testcontainers.rabbitmq.RabbitMQContainer[] or avadoc:org.testcontainers.activemq.ActiveMQContainer[] or javadoc:org.testcontainers.activemq.ArtemisContainer[]
133+
131134
| javadoc:org.springframework.boot.artemis.autoconfigure.ArtemisConnectionDetails[]
132135
| Containers of type javadoc:org.testcontainers.activemq.ArtemisContainer[]
133136

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2012-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docs.messaging.amqp.generic.receiving;
18+
19+
import org.springframework.amqp.client.annotation.AmqpListener;
20+
import org.springframework.stereotype.Component;
21+
22+
@Component
23+
public class MyBean {
24+
25+
@AmqpListener(addresses = "/queues/someQueue")
26+
public void processMessage(String content) {
27+
// ...
28+
}
29+
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2012-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docs.messaging.amqp.generic.receiving.custom;
18+
19+
import org.springframework.amqp.client.AmqpConnectionFactory;
20+
import org.springframework.amqp.client.config.MethodAmqpMessageListenerContainerFactory;
21+
import org.springframework.boot.amqp.autoconfigure.AmqpMessageListenerContainerFactoryConfigurer;
22+
import org.springframework.context.annotation.Bean;
23+
import org.springframework.context.annotation.Configuration;
24+
25+
@Configuration(proxyBeanMethods = false)
26+
public class MyAmqpConfiguration {
27+
28+
@Bean
29+
public MethodAmqpMessageListenerContainerFactory myFactory(AmqpMessageListenerContainerFactoryConfigurer configurer,
30+
AmqpConnectionFactory connectionFactory) {
31+
MethodAmqpMessageListenerContainerFactory factory = new MethodAmqpMessageListenerContainerFactory(
32+
connectionFactory);
33+
configurer.configure(factory);
34+
factory.setMessageConverter(new MyMessageConverter());
35+
return factory;
36+
}
37+
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2012-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docs.messaging.amqp.generic.receiving.custom;
18+
19+
import org.springframework.amqp.client.annotation.AmqpListener;
20+
import org.springframework.stereotype.Component;
21+
22+
@Component
23+
public class MyBean {
24+
25+
@AmqpListener(addresses = "/queues/someQueue", containerFactory = "myFactory")
26+
public void processMessage(String content) {
27+
// ...
28+
}
29+
30+
}

documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/amqp/receiving/custom/MyMessageConverter.java renamed to documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/amqp/generic/receiving/custom/MyMessageConverter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.docs.messaging.amqp.receiving.custom;
17+
package org.springframework.boot.docs.messaging.amqp.generic.receiving.custom;
1818

1919
import org.springframework.amqp.core.Message;
2020
import org.springframework.amqp.core.MessageProperties;

0 commit comments

Comments
 (0)