Skip to content

Commit 8fa1eee

Browse files
garyrussellartembilan
authored andcommitted
Add SimplePropertyValueConnectionNameStrategy
* Unused imports * Doc polishing * Polishing - PR comments; early use of environment
1 parent 8bb92e5 commit 8fa1eee

File tree

3 files changed

+112
-2
lines changed

3 files changed

+112
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2018 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+
* http://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.amqp.rabbit.connection;
18+
19+
import org.springframework.context.EnvironmentAware;
20+
import org.springframework.core.env.Environment;
21+
import org.springframework.util.Assert;
22+
23+
/**
24+
* A {@link ConnectionNameStrategy} that returns the value of a (required) property. If
25+
* the property does not exist, the connection will be given the name of the property.
26+
*
27+
* @author Gary Russell
28+
* @since 2.1
29+
*
30+
*/
31+
public class SimplePropertyValueConnectionNameStrategy implements ConnectionNameStrategy, EnvironmentAware {
32+
33+
private final String propertyName;
34+
35+
private String propertyValue;
36+
37+
private Environment environment;
38+
39+
public SimplePropertyValueConnectionNameStrategy(String propertyName) {
40+
Assert.notNull(propertyName, "'propertyName' cannot be null");
41+
this.propertyName = propertyName;
42+
}
43+
44+
@Override
45+
public void setEnvironment(Environment environment) {
46+
this.environment = environment;
47+
}
48+
49+
@Override
50+
public String obtainNewConnectionName(ConnectionFactory connectionFactory) {
51+
if (this.propertyValue == null) {
52+
if (this.environment != null) {
53+
this.propertyValue = this.environment.getProperty(this.propertyName);
54+
}
55+
if (this.propertyValue == null) {
56+
this.propertyValue = this.propertyName;
57+
}
58+
}
59+
return this.propertyValue;
60+
}
61+
62+
}

spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/EnableRabbitIntegrationTests.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@
7272
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
7373
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerEndpoint;
7474
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
75+
import org.springframework.amqp.rabbit.connection.Connection;
7576
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
77+
import org.springframework.amqp.rabbit.connection.ConnectionNameStrategy;
78+
import org.springframework.amqp.rabbit.connection.SimplePropertyValueConnectionNameStrategy;
7679
import org.springframework.amqp.rabbit.core.RabbitAdmin;
7780
import org.springframework.amqp.rabbit.core.RabbitManagementTemplate;
7881
import org.springframework.amqp.rabbit.core.RabbitTemplate;
@@ -128,6 +131,7 @@
128131
import org.springframework.test.context.TestContext;
129132
import org.springframework.test.context.TestExecutionListeners;
130133
import org.springframework.test.context.TestExecutionListeners.MergeMode;
134+
import org.springframework.test.context.TestPropertySource;
131135
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
132136
import org.springframework.test.context.support.AbstractTestExecutionListener;
133137
import org.springframework.transaction.PlatformTransactionManager;
@@ -151,6 +155,7 @@
151155
@DirtiesContext
152156
@TestExecutionListeners(mergeMode = MergeMode.MERGE_WITH_DEFAULTS,
153157
listeners = EnableRabbitIntegrationTests.DeleteQueuesExecutionListener.class)
158+
@TestPropertySource(properties = "spring.application.name=testConnectionName")
154159
public class EnableRabbitIntegrationTests {
155160

156161
@ClassRule
@@ -209,6 +214,9 @@ public class EnableRabbitIntegrationTests {
209214
@Autowired
210215
private MetaListener metaListener;
211216

217+
@Autowired
218+
private CachingConnectionFactory connectionFactory;
219+
212220
@BeforeClass
213221
public static void setUp() {
214222
System.setProperty(RabbitListenerAnnotationBeanPostProcessor.RABBIT_EMPTY_STRING_ARGUMENTS_PROPERTY,
@@ -796,6 +804,13 @@ public void testNoListenerYet() throws Exception {
796804
assertThat(new String(config.message.getBody()), equalTo("bar"));
797805
}
798806

807+
@Test
808+
public void connectionName() {
809+
Connection conn = this.connectionFactory.createConnection();
810+
conn.close();
811+
assertThat(conn.getDelegate().getClientProvidedName(), equalTo("testConnectionName"));
812+
}
813+
799814
interface TxService {
800815

801816
@Transactional
@@ -1243,6 +1258,11 @@ public static class EnableRabbitConfig {
12431258

12441259
private final CountDownLatch noListenerLatch = new CountDownLatch(1);
12451260

1261+
@Bean
1262+
public ConnectionNameStrategy cns() {
1263+
return new SimplePropertyValueConnectionNameStrategy("spring.application.name");
1264+
}
1265+
12461266
@Bean
12471267
public static ProxyListenerBPP listenerProxier() { // note static
12481268
return new ProxyListenerBPP();
@@ -1449,6 +1469,7 @@ public ConnectionFactory rabbitConnectionFactory() {
14491469
executor.setThreadNamePrefix("rabbitClientThread-");
14501470
executor.afterPropertiesSet();
14511471
connectionFactory.setExecutor(executor);
1472+
connectionFactory.setConnectionNameStrategy(cns());
14521473
return connectionFactory;
14531474
}
14541475

src/reference/asciidoc/amqp.adoc

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@ Here's an example with a custom thread factory that prefixes thread names with `
346346
347347
----
348348

349+
===== Naming Connections
350+
349351
Starting with _version 1.7_ a `ConnectionNameStrategy` is provided for the injection into the `AbstractionConnectionFactory`.
350352
The generated name is used for the application-specific identification of the target RabbitMQ connection.
351353
The connection name is displayed in the management UI if the RabbitMQ server supports it.
@@ -361,6 +363,31 @@ The `ConnectionFactory` argument can be used to distinguish target connection na
361363
By default, the `beanName` of the `AbstractConnectionFactory`, a hex String representing the object, and an internal counter are used to generate the `connection_name`.
362364
The `<rabbit:connection-factory>` namespace component is also supplied with the `connection-name-strategy` attribute.
363365

366+
An implementation `SimplePropertyValueConnectionNameStrategy` is provided that sets the connection name to an application property.
367+
Declare it as a `@Bean` and inject it into the connection factory:
368+
369+
[source, java]
370+
----
371+
@Bean
372+
public ConnectionNameStrategy cns() {
373+
return new SimplePropertyValueConnectionNameStrategy("spring.application.name");
374+
}
375+
376+
@Bean
377+
public ConnectionFactory rabbitConnectionFactory(ConnectionNameStrategy cns) {
378+
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
379+
...
380+
connectionFactory.setConnectionNameStrategy(cns);
381+
return connectionFactory;
382+
}
383+
----
384+
385+
The property must exist in the application context's `Environment`.
386+
387+
NOTE: When using Spring Boot and it's autoconfigured connection factory, it is only necessary to declare the `ConnectionNameStrategy` `@Bean`.
388+
Boot will auto-detect the bean and wire it into the factory.
389+
390+
===== Blocked Connections and Resource Constraints
364391

365392
The connection might be blocked for interaction from the Broker according to the https://www.rabbitmq.com/memory.html[Memory Alarm].
366393
Starting with _version 2.0_, the `org.springframework.amqp.rabbit.connection.Connection` can be supplied with `com.rabbitmq.client.BlockedListener` s to to be notified for connection blocked and unblocked events.
@@ -370,8 +397,8 @@ These allow you to provide application logic to react appropriately to problems
370397
IMPORTANT: When the application is configured with a single `CachingConnectionFactory`, as it is by default with Spring Boot auto-configuration, the application will stop working when the connection is blocked by the Broker.
371398
And when it is blocked by the Broker, any its clients stop to work.
372399
If we have producers and consumers in the same application, we may end up with a deadlock when producers are blocking the connection because there are no resources on the Broker anymore and consumers can't free them because the connection is blocked.
373-
To mitigate the problem, there is just enough to have one more separate `CachingConnectionFactory` instance with the same options - one for producers and one for consumers.
374-
The separate `CachingConnectionFactory` isn't recommended for transactional producers, since they should reuse a `Channel` associated with the consumer transactions.
400+
To mitigate the problem, it is suggested to have one more separate `CachingConnectionFactory` instance with the same options - one for producers and one for consumers.
401+
A separate `CachingConnectionFactory` isn't possible for transactional producers that execute on a consumer thread, since they should reuse the `Channel` associated with the consumer transactions.
375402

376403
Starting with _version 2.0.2_, the `RabbitTemplate` has a configuration option to automatically use a second connection factory, unless transactions are being used.
377404
See <<separate-connection>> for more information.

0 commit comments

Comments
 (0)