Skip to content

Commit 9fd9472

Browse files
committed
Better customization of the auto-configured ActiveMQConnectionFactory
This commit exposes additional properties and a callback interface to further tune the auto-configured ActiveMQConnectionFactory. Closes gh-9667
1 parent 9a34d95 commit 9fd9472

File tree

9 files changed

+234
-41
lines changed

9 files changed

+234
-41
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616

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

19+
import java.util.List;
20+
1921
import javax.jms.ConnectionFactory;
2022

2123
import org.apache.activemq.ActiveMQConnectionFactory;
2224
import org.apache.activemq.pool.PooledConnectionFactory;
2325

26+
import org.springframework.beans.factory.ObjectProvider;
2427
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2528
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2629
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -44,9 +47,11 @@ class ActiveMQConnectionFactoryConfiguration {
4447

4548
@Bean
4649
@ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "false", matchIfMissing = true)
47-
public ActiveMQConnectionFactory jmsConnectionFactory(ActiveMQProperties properties) {
48-
return new ActiveMQConnectionFactoryFactory(properties)
49-
.createConnectionFactory(ActiveMQConnectionFactory.class);
50+
public ActiveMQConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,
51+
ObjectProvider<List<ActiveMQConnectionFactoryCustomizer>> factoryCustomizers) {
52+
return new ActiveMQConnectionFactoryFactory(properties,
53+
factoryCustomizers.getIfAvailable()).createConnectionFactory(
54+
ActiveMQConnectionFactory.class);
5055
}
5156

5257
@ConditionalOnClass(PooledConnectionFactory.class)
@@ -56,10 +61,12 @@ static class PooledConnectionFactoryConfiguration {
5661
@ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "true", matchIfMissing = false)
5762
@ConfigurationProperties(prefix = "spring.activemq.pool.configuration")
5863
public PooledConnectionFactory pooledJmsConnectionFactory(
59-
ActiveMQProperties properties) {
64+
ActiveMQProperties properties,
65+
ObjectProvider<List<ActiveMQConnectionFactoryCustomizer>> factoryCustomizers) {
6066
PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory(
61-
new ActiveMQConnectionFactoryFactory(properties)
62-
.createConnectionFactory(ActiveMQConnectionFactory.class));
67+
new ActiveMQConnectionFactoryFactory(properties,
68+
factoryCustomizers.getIfAvailable()).createConnectionFactory(
69+
ActiveMQConnectionFactory.class));
6370
ActiveMQProperties.Pool pool = properties.getPool();
6471
pooledConnectionFactory.setBlockIfSessionPoolIsFull(pool.isBlockIfFull());
6572
pooledConnectionFactory.setBlockIfSessionPoolIsFullTimeout(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2012-2017 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.boot.autoconfigure.jms.activemq;
18+
19+
import org.apache.activemq.ActiveMQConnectionFactory;
20+
21+
/**
22+
* Callback interface that can be implemented by beans wishing to customize the
23+
* {@link ActiveMQConnectionFactory} whilst retaining default auto-configuration.
24+
*
25+
* @author Stephane Nicoll
26+
* @since 1.5.5
27+
*/
28+
public interface ActiveMQConnectionFactoryCustomizer {
29+
30+
/**
31+
* Customize the {@link ActiveMQConnectionFactory}.
32+
* @param factory the factory to customize
33+
*/
34+
void customize(ActiveMQConnectionFactory factory);
35+
36+
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryFactory.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2017 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.
@@ -17,6 +17,8 @@
1717
package org.springframework.boot.autoconfigure.jms.activemq;
1818

1919
import java.lang.reflect.InvocationTargetException;
20+
import java.util.Collections;
21+
import java.util.List;
2022

2123
import org.apache.activemq.ActiveMQConnectionFactory;
2224

@@ -40,9 +42,14 @@ class ActiveMQConnectionFactoryFactory {
4042

4143
private final ActiveMQProperties properties;
4244

43-
ActiveMQConnectionFactoryFactory(ActiveMQProperties properties) {
45+
private final List<ActiveMQConnectionFactoryCustomizer> factoryCustomizers;
46+
47+
ActiveMQConnectionFactoryFactory(ActiveMQProperties properties,
48+
List<ActiveMQConnectionFactoryCustomizer> factoryCustomizers) {
4449
Assert.notNull(properties, "Properties must not be null");
4550
this.properties = properties;
51+
this.factoryCustomizers = (factoryCustomizers != null ? factoryCustomizers
52+
: Collections.<ActiveMQConnectionFactoryCustomizer>emptyList());
4653
}
4754

4855
public <T extends ActiveMQConnectionFactory> T createConnectionFactory(
@@ -59,13 +66,17 @@ public <T extends ActiveMQConnectionFactory> T createConnectionFactory(
5966
private <T extends ActiveMQConnectionFactory> T doCreateConnectionFactory(
6067
Class<T> factoryClass) throws Exception {
6168
T factory = createConnectionFactoryInstance(factoryClass);
69+
factory.setCloseTimeout(this.properties.getCloseTimeout());
70+
factory.setNonBlockingRedelivery(this.properties.isNonBlockingRedelivery());
71+
factory.setSendTimeout(this.properties.getSendTimeout());
6272
Packages packages = this.properties.getPackages();
6373
if (packages.getTrustAll() != null) {
6474
factory.setTrustAllPackages(packages.getTrustAll());
6575
}
6676
if (!packages.getTrusted().isEmpty()) {
6777
factory.setTrustedPackages(packages.getTrusted());
6878
}
79+
customize(factory);
6980
return factory;
7081
}
7182

@@ -82,6 +93,12 @@ private <T extends ActiveMQConnectionFactory> T createConnectionFactoryInstance(
8293
return factoryClass.getConstructor(String.class).newInstance(brokerUrl);
8394
}
8495

96+
private void customize(ActiveMQConnectionFactory connectionFactory) {
97+
for (ActiveMQConnectionFactoryCustomizer factoryCustomizer : this.factoryCustomizers) {
98+
factoryCustomizer.customize(connectionFactory);
99+
}
100+
}
101+
85102
String determineBrokerUrl() {
86103
if (this.properties.getBrokerUrl() != null) {
87104
return this.properties.getBrokerUrl();

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,24 @@ public class ActiveMQProperties {
5353
*/
5454
private String password;
5555

56+
/**
57+
* Time to wait, in milliseconds, before considering a close complete.
58+
*/
59+
private int closeTimeout = 15000;
60+
61+
/**
62+
* Do not stop message delivery before re-delivering messages from a rolled back
63+
* transaction. This implies that message order will not be preserved when this is
64+
* enabled.
65+
*/
66+
private boolean nonBlockingRedelivery = false;
67+
68+
/**
69+
* Time to wait, in milliseconds, on Message sends for a response. Set it to 0 to
70+
* indicate to wait forever.
71+
*/
72+
private int sendTimeout = 0;
73+
5674
private Pool pool = new Pool();
5775

5876
private Packages packages = new Packages();
@@ -89,6 +107,30 @@ public void setPassword(String password) {
89107
this.password = password;
90108
}
91109

110+
public int getCloseTimeout() {
111+
return this.closeTimeout;
112+
}
113+
114+
public void setCloseTimeout(int closeTimeout) {
115+
this.closeTimeout = closeTimeout;
116+
}
117+
118+
public boolean isNonBlockingRedelivery() {
119+
return this.nonBlockingRedelivery;
120+
}
121+
122+
public void setNonBlockingRedelivery(boolean nonBlockingRedelivery) {
123+
this.nonBlockingRedelivery = nonBlockingRedelivery;
124+
}
125+
126+
public int getSendTimeout() {
127+
return this.sendTimeout;
128+
}
129+
130+
public void setSendTimeout(int sendTimeout) {
131+
this.sendTimeout = sendTimeout;
132+
}
133+
92134
public Pool getPool() {
93135
return this.pool;
94136
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQXAConnectionFactoryConfiguration.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2017 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.
@@ -16,12 +16,15 @@
1616

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

19+
import java.util.List;
20+
1921
import javax.jms.ConnectionFactory;
2022
import javax.transaction.TransactionManager;
2123

2224
import org.apache.activemq.ActiveMQConnectionFactory;
2325
import org.apache.activemq.ActiveMQXAConnectionFactory;
2426

27+
import org.springframework.beans.factory.ObjectProvider;
2528
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2629
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2730
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -47,18 +50,22 @@ class ActiveMQXAConnectionFactoryConfiguration {
4750
@Primary
4851
@Bean(name = { "jmsConnectionFactory", "xaJmsConnectionFactory" })
4952
public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,
53+
ObjectProvider<List<ActiveMQConnectionFactoryCustomizer>> factoryCustomizers,
5054
XAConnectionFactoryWrapper wrapper) throws Exception {
5155
ActiveMQXAConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
52-
properties).createConnectionFactory(ActiveMQXAConnectionFactory.class);
56+
properties, factoryCustomizers.getIfAvailable())
57+
.createConnectionFactory(ActiveMQXAConnectionFactory.class);
5358
return wrapper.wrapConnectionFactory(connectionFactory);
5459
}
5560

5661
@Bean
5762
@ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "false", matchIfMissing = true)
5863
public ActiveMQConnectionFactory nonXaJmsConnectionFactory(
59-
ActiveMQProperties properties) {
60-
return new ActiveMQConnectionFactoryFactory(properties)
61-
.createConnectionFactory(ActiveMQConnectionFactory.class);
64+
ActiveMQProperties properties,
65+
ObjectProvider<List<ActiveMQConnectionFactoryCustomizer>> factoryCustomizers) {
66+
return new ActiveMQConnectionFactoryFactory(properties,
67+
factoryCustomizers.getIfAvailable()).createConnectionFactory(
68+
ActiveMQConnectionFactory.class);
6269
}
6370

6471
}

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,54 @@ public void configurationBacksOffWhenCustomConnectionFactoryExists() {
6161
.isTrue();
6262
}
6363

64+
@Test
65+
public void defaultsConnectionFactoryAreApplied() {
66+
load(EmptyConfiguration.class, "spring.activemq.pool.enabled=false");
67+
assertThat(this.context.getBeansOfType(ActiveMQConnectionFactory.class)).hasSize(1);
68+
ActiveMQConnectionFactory connectionFactory = this.context.getBean(
69+
ActiveMQConnectionFactory.class);
70+
ActiveMQConnectionFactory defaultFactory = new ActiveMQConnectionFactory(
71+
"vm://localhost?broker.persistent=false");
72+
assertThat(connectionFactory.getUserName()).isEqualTo(
73+
defaultFactory.getUserName());
74+
assertThat(connectionFactory.getPassword()).isEqualTo(
75+
defaultFactory.getPassword());
76+
assertThat(connectionFactory.getCloseTimeout()).isEqualTo(
77+
defaultFactory.getCloseTimeout());
78+
assertThat(connectionFactory.isNonBlockingRedelivery()).isEqualTo(
79+
defaultFactory.isNonBlockingRedelivery());
80+
assertThat(connectionFactory.getSendTimeout()).isEqualTo(
81+
defaultFactory.getSendTimeout());
82+
assertThat(connectionFactory.isTrustAllPackages()).isEqualTo(
83+
defaultFactory.isTrustAllPackages());
84+
assertThat(connectionFactory.getTrustedPackages()).containsExactly(
85+
defaultFactory.getTrustedPackages().toArray(new String[]{}));
86+
}
87+
88+
@Test
89+
public void customConnectionFactoryAreApplied() {
90+
load(EmptyConfiguration.class, "spring.activemq.pool.enabled=false",
91+
"spring.activemq.brokerUrl=vm://localhost?useJmx=false&broker.persistent=false",
92+
"spring.activemq.user=foo",
93+
"spring.activemq.password=bar",
94+
"spring.activemq.closeTimeout=500",
95+
"spring.activemq.nonBlockingRedelivery=true",
96+
"spring.activemq.sendTimeout=1000",
97+
"spring.activemq.packages.trust-all=false",
98+
"spring.activemq.packages.trusted=com.example.acme");
99+
assertThat(this.context.getBeansOfType(ActiveMQConnectionFactory.class)).hasSize(1);
100+
ActiveMQConnectionFactory connectionFactory = this.context.getBean(
101+
ActiveMQConnectionFactory.class);
102+
assertThat(connectionFactory.getUserName()).isEqualTo("foo");
103+
assertThat(connectionFactory.getPassword()).isEqualTo("bar");
104+
assertThat(connectionFactory.getCloseTimeout()).isEqualTo(500);
105+
assertThat(connectionFactory.isNonBlockingRedelivery()).isEqualTo(true);
106+
assertThat(connectionFactory.getSendTimeout()).isEqualTo(1000);
107+
assertThat(connectionFactory.isTrustAllPackages()).isFalse();
108+
assertThat(connectionFactory.getTrustedPackages()).containsExactly(
109+
"com.example.acme");
110+
}
111+
64112
@Test
65113
public void defaultsPooledConnectionFactoryAreApplied() {
66114
load(EmptyConfiguration.class, "spring.activemq.pool.enabled=true");
@@ -161,6 +209,16 @@ public void pooledConnectionFactoryConfiguration() throws JMSException {
161209
assertThat(connectionFactory.createConnection()).isNull();
162210
}
163211

212+
@Test
213+
public void customizerOverridesAutConfig() {
214+
load(CustomizerConfiguration.class);
215+
ActiveMQConnectionFactory connectionFactory = this.context.getBean(
216+
ActiveMQConnectionFactory.class);
217+
assertThat(connectionFactory.getBrokerURL()).isEqualTo(
218+
"vm://localhost?useJmx=false&broker.persistent=false");
219+
assertThat(connectionFactory.getUserName()).isEqualTo("foobar");
220+
}
221+
164222
private void load(Class<?> config, String... environment) {
165223
this.context = doLoad(config, environment);
166224
}
@@ -191,4 +249,20 @@ public ConnectionFactory connectionFactory() {
191249

192250
}
193251

252+
@Configuration
253+
static class CustomizerConfiguration {
254+
255+
@Bean
256+
public ActiveMQConnectionFactoryCustomizer activeMQConnectionFactoryCustomizer() {
257+
return new ActiveMQConnectionFactoryCustomizer() {
258+
@Override
259+
public void customize(ActiveMQConnectionFactory factory) {
260+
factory.setBrokerURL(
261+
"vm://localhost?useJmx=false&broker.persistent=false");
262+
factory.setUserName("foobar");
263+
}
264+
};
265+
}
266+
}
267+
194268
}

0 commit comments

Comments
 (0)