Skip to content

Commit 49040a2

Browse files
committed
Add back-off attribute to JMS namespace
This commit adds a "back-off" attribute to the jms:listener-container element so that a BackOff instance can be provided for users of the XML namespace. Issue: SPR-11746
1 parent 6a04831 commit 49040a2

File tree

6 files changed

+73
-18
lines changed

6 files changed

+73
-18
lines changed

spring-jms/src/main/java/org/springframework/jms/config/JmsListenerContainerParser.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class JmsListenerContainerParser extends AbstractListenerContainerParser {
5454

5555
private static final String RECOVERY_INTERVAL_ATTRIBUTE = "recovery-interval";
5656

57+
private static final String BACK_OFF_ATTRIBUTE = "back-off";
58+
5759

5860
protected PropertyValues parseProperties(Element containerEle, ParserContext parserContext) {
5961
final MutablePropertyValues properties = new MutablePropertyValues();
@@ -223,10 +225,18 @@ private PropertyValues parseContainerProperties(Element containerEle,
223225
}
224226
}
225227

226-
String recoveryInterval = containerEle.getAttribute(RECOVERY_INTERVAL_ATTRIBUTE);
227-
if (StringUtils.hasText(recoveryInterval)) {
228+
String backOffBeanName = containerEle.getAttribute(BACK_OFF_ATTRIBUTE);
229+
if (StringUtils.hasText(backOffBeanName)) {
228230
if (!isSimpleContainer) {
229-
propertyValues.add("recoveryInterval", recoveryInterval);
231+
propertyValues.add("backOff", new RuntimeBeanReference(backOffBeanName));
232+
}
233+
}
234+
else { // No need to consider this if back-off is set
235+
String recoveryInterval = containerEle.getAttribute(RECOVERY_INTERVAL_ATTRIBUTE);
236+
if (StringUtils.hasText(recoveryInterval)) {
237+
if (!isSimpleContainer) {
238+
propertyValues.add("recoveryInterval", recoveryInterval);
239+
}
230240
}
231241
}
232242

spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,16 +224,19 @@ public void setTaskExecutor(Executor taskExecutor) {
224224
* between recovery attempts. If the {@link BackOff} implementation
225225
* returns {@link BackOff#STOP}, this listener container will not further
226226
* attempt to recover.
227+
* <p>The {@link #setRecoveryInterval(long) recovery interval} is ignored
228+
* when this property is set.
227229
*/
228230
public void setBackOff(BackOff backOff) {
229231
this.backOff = backOff;
230232
}
231233

232234
/**
233235
* Specify the interval between recovery attempts, in <b>milliseconds</b>.
234-
* The default is 5000 ms, that is, 5 seconds.
235-
* <p>This is a convenience method to create a {@link FixedBackOff} with
236-
* the specified interval.
236+
* The default is 5000 ms, that is, 5 seconds. This is a convenience method
237+
* to create a {@link FixedBackOff} with the specified interval.
238+
* <p>For more recovery options, consider specifying a {@link BackOff}
239+
* instance instead.
237240
* @see #setBackOff(BackOff)
238241
* @see #handleListenerSetupFailure
239242
*/

spring-jms/src/main/resources/org/springframework/jms/config/spring-jms-4.1.xsd

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,11 +318,29 @@
318318
]]></xsd:documentation>
319319
</xsd:annotation>
320320
</xsd:attribute>
321+
<xsd:attribute name="back-off" type="xsd:string">
322+
<xsd:annotation>
323+
<xsd:documentation><![CDATA[
324+
Specify the BackOff instance to use to compute the interval between recovery
325+
attempts. If the BackOff implementation returns "BackOff#STOP", the listener
326+
container will not further attempt to recover. The recovery-interval value is
327+
ignored when this property is set. The default is a FixedBackOff with an
328+
interval of 5000 ms, that is 5 seconds.
329+
]]></xsd:documentation>
330+
<xsd:appinfo>
331+
<tool:annotation kind="ref">
332+
<tool:expected-type type="org.springframework.util.BackOff"/>
333+
</tool:annotation>
334+
</xsd:appinfo>
335+
</xsd:annotation>
336+
</xsd:attribute>
321337
<xsd:attribute name="recovery-interval" type="xsd:string">
322338
<xsd:annotation>
323339
<xsd:documentation><![CDATA[
324-
Specify the interval between recovery attempts, in milliseconds.
325-
The default is 5000 ms, that is, 5 seconds.
340+
Specify the interval between recovery attempts, in milliseconds. Convenience
341+
way to create a FixedBackOff with the specified interval. For more recovery
342+
options, consider specifying a BackOff instance instead. The default is
343+
5000 ms, that is 5 seconds.
326344
]]></xsd:documentation>
327345
</xsd:annotation>
328346
</xsd:attribute>

spring-jms/src/test/java/org/springframework/jms/config/JmsNamespaceHandlerTests.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ public void testJmsContainerFactoryConfiguration() {
161161
assertEquals("wrong concurrency", 3, container.getConcurrentConsumers());
162162
assertEquals("wrong concurrency", 5, container.getMaxConcurrentConsumers());
163163
assertEquals("wrong prefetch", 50, container.getMaxMessagesPerTask());
164+
assertSame(context.getBean("testBackOff"),new DirectFieldAccessor(container).getPropertyValue("backOff"));
164165

165166
assertEquals("phase cannot be customized by the factory", Integer.MAX_VALUE, container.getPhase());
166167
}
@@ -216,12 +217,13 @@ public void testListeners() throws Exception {
216217

217218
@Test
218219
public void testRecoveryInterval() {
219-
long recoveryInterval1 = getRecoveryInterval("listener1");
220-
long recoveryInterval2 = getRecoveryInterval("listener2");
220+
Object testBackOff = context.getBean("testBackOff");
221+
BackOff backOff1 = getBackOff("listener1");
222+
BackOff backOff2 = getBackOff("listener2");
221223
long recoveryInterval3 = getRecoveryInterval(DefaultMessageListenerContainer.class.getName() + "#0");
222224

223-
assertEquals(1000L, recoveryInterval1);
224-
assertEquals(1000L, recoveryInterval2);
225+
assertSame(testBackOff, backOff1);
226+
assertSame(testBackOff, backOff2);
225227
assertEquals(DefaultMessageListenerContainer.DEFAULT_RECOVERY_INTERVAL, recoveryInterval3);
226228
}
227229

@@ -300,9 +302,13 @@ private ErrorHandler getErrorHandler(String containerBeanName) {
300302
return (ErrorHandler) new DirectFieldAccessor(container).getPropertyValue("errorHandler");
301303
}
302304

303-
private long getRecoveryInterval(String containerBeanName) {
305+
private BackOff getBackOff(String containerBeanName) {
304306
DefaultMessageListenerContainer container = this.context.getBean(containerBeanName, DefaultMessageListenerContainer.class);
305-
BackOff backOff = (BackOff) new DirectFieldAccessor(container).getPropertyValue("backOff");
307+
return (BackOff) new DirectFieldAccessor(container).getPropertyValue("backOff");
308+
}
309+
310+
private long getRecoveryInterval(String containerBeanName) {
311+
BackOff backOff = getBackOff(containerBeanName);
306312
assertEquals(FixedBackOff.class, backOff.getClass());
307313
return ((FixedBackOff)backOff).getInterval();
308314
}

spring-jms/src/test/resources/org/springframework/jms/config/jmsNamespaceHandlerTests.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
connection-factory="testConnectionFactory" task-executor="testTaskExecutor"
1010
destination-resolver="testDestinationResolver" message-converter="testMessageConverter"
1111
transaction-manager="testTransactionManager" error-handler="testErrorHandler"
12-
cache="connection" concurrency="3-5" prefetch="50" receive-timeout="100" recovery-interval="1000" phase="99">
12+
cache="connection" concurrency="3-5" prefetch="50" receive-timeout="100" back-off="testBackOff" phase="99">
1313
<jms:listener id="listener1" destination="testDestination" ref="testBean1" method="setName"/>
1414
<jms:listener id="listener2" destination="testDestination" ref="testBean2" method="setName" response-destination="responseDestination"/>
1515
</jms:listener-container>
@@ -43,7 +43,8 @@
4343
connection-factory="testConnectionFactory" task-executor="testTaskExecutor"
4444
destination-resolver="testDestinationResolver" message-converter="testMessageConverter"
4545
transaction-manager="testTransactionManager" error-handler="testErrorHandler"
46-
concurrency="3-5" prefetch="50" receive-timeout="100" recovery-interval="1000"/>
46+
concurrency="3-5" prefetch="50" receive-timeout="100"
47+
recovery-interval="1000" back-off="testBackOff"/>
4748

4849
<!-- the default ConnectionFactory -->
4950
<bean id="connectionFactory" class="org.springframework.jms.StubConnectionFactory"/>
@@ -67,6 +68,10 @@
6768

6869
<bean id="testErrorHandler" class="org.springframework.jms.config.JmsNamespaceHandlerTests$TestErrorHandler"/>
6970

71+
<bean id="testBackOff" class="org.springframework.util.FixedBackOff">
72+
<property name="interval" value="1000"/>
73+
</bean>
74+
7075
<bean id="testBean1" class="org.springframework.tests.sample.beans.TestBean"/>
7176

7277
<bean id="testBean2" class="org.springframework.tests.sample.beans.TestBean"/>

src/asciidoc/index.adoc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40424,6 +40424,10 @@ This listener container strikes a good balance between low requirements on the J
4042440424
provider, advanced functionality such as transaction participation, and compatibility
4042540425
with Java EE environments.
4042640426

40427+
This container also has recoverable capabilities when the broker goes down. By default,
40428+
a simple `BackOff` implementation retries every 5 seconds. It is possible to specify
40429+
a custom `BackOff` implementation for more fine-grained recovery options, see
40430+
`ExponentialBackOff` for an example.
4042740431

4042840432

4042940433
[[jms-tx]]
@@ -41427,9 +41431,18 @@ choices and message redelivery scenarios.
4142741431
| The timeout to use for receive calls (in milliseconds). The default is `1000` ms (1
4142841432
sec); `-1` indicates no timeout at all.
4142941433

41434+
| back-off
41435+
| Specify the `BackOff` instance to use to compute the interval between recovery
41436+
attempts. If the `BackOff` implementation returns `BackOff#STOP`, the listener
41437+
container will not further attempt to recover. The `recovery-interval value is
41438+
is ignored when this property is set. The default is a `FixedBackOff` with an
41439+
interval of 5000 ms, that is 5 seconds.
41440+
4143041441
| recovery-interval
41431-
| Specify the interval between recovery attempts, in milliseconds. The default is `5000`
41432-
ms, that is, 5 seconds.
41442+
| Specify the interval between recovery attempts, in milliseconds. Convenience
41443+
way to create a `FixedBackOff` with the specified interval. For more recovery
41444+
options, consider specifying a BackOff instance instead. The default is 5000 ms,
41445+
that is 5 seconds.
4143341446

4143441447
| phase
4143541448
| The lifecycle phase within which this container should start and stop. The lower the

0 commit comments

Comments
 (0)