diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/AbstractMessageListenerContainer.java b/spring-jms/src/main/java/org/springframework/jms/listener/AbstractMessageListenerContainer.java
index 6642e4fcdfc..3605debf708 100644
--- a/spring-jms/src/main/java/org/springframework/jms/listener/AbstractMessageListenerContainer.java
+++ b/spring-jms/src/main/java/org/springframework/jms/listener/AbstractMessageListenerContainer.java
@@ -37,19 +37,19 @@ import org.springframework.util.ErrorHandler;
import org.springframework.util.ReflectionUtils;
/**
- * Abstract base class for message listener containers. Can either host
- * a standard JMS {@link javax.jms.MessageListener} or a Spring-specific
- * {@link SessionAwareMessageListener}.
+ * Abstract base class for Spring message listener container implementations.
+ * Can either host a standard JMS {@link javax.jms.MessageListener} or Spring's
+ * {@link SessionAwareMessageListener} for actual message processing.
*
- *
Usually holds a single JMS {@link Connection} that all listeners are
- * supposed to be registered on, which is the standard JMS way of managing
- * listeners. Can alternatively also be used with a fresh Connection per
- * listener, for J2EE-style XA-aware JMS messaging. The actual registration
- * process is up to concrete subclasses.
+ *
Usually holds a single JMS {@link Connection} that all listeners are supposed
+ * to be registered on, which is the standard JMS way of managing listener sessions.
+ * Can alternatively also be used with a fresh Connection per listener, for Java EE
+ * style XA-aware JMS messaging. The actual registration process is up to concrete
+ * subclasses.
*
- *
NOTE: The default behavior of this message listener container
- * is to never propagate an exception thrown by a message listener up to
- * the JMS provider. Instead, it will log any such exception at the error level.
+ *
NOTE: The default behavior of this message listener container is to
+ * never propagate an exception thrown by a message listener up to the JMS
+ * provider. Instead, it will log any such exception at the error level.
* This means that from the perspective of the attendant JMS provider no such
* listener will ever fail. However, if error handling is necessary, then
* any implementation of the {@link ErrorHandler} strategy may be provided to
@@ -62,37 +62,48 @@ import org.springframework.util.ReflectionUtils;
*
"sessionAcknowledgeMode" set to "AUTO_ACKNOWLEDGE" (default):
* This mode is container-dependent: For {@link DefaultMessageListenerContainer},
* it means automatic message acknowledgment before listener execution, with
- * no redelivery in case of an exception. For {@link SimpleMessageListenerContainer},
+ * no redelivery in case of an exception and no redelivery in case of other listener
+ * execution interruptions either. For {@link SimpleMessageListenerContainer},
* it means automatic message acknowledgment after listener execution, with
- * redelivery in case of an exception thrown, as defined by the JMS specification.
- * In order to consistently achieve the latter behavior with any container variant,
- * consider setting "sessionTransacted" to "true" instead.
+ * no redelivery in case of a user exception thrown but potential redelivery in case
+ * of the JVM dying during listener execution. In order to consistently arrange for
+ * redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or -
+ * preferably - setting "sessionTransacted" to "true" instead.
+ * "sessionAcknowledgeMode" set to "DUPS_OK_ACKNOWLEDGE":
+ * Lazy message acknowledgment during ({@link DefaultMessageListenerContainer})
+ * or shortly after ({@link SimpleMessageListenerContainer}) listener execution;
+ * no redelivery in case of a user exception thrown but potential redelivery in case
+ * of the JVM dying during listener execution. In order to consistently arrange for
+ * redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or -
+ * preferably - setting "sessionTransacted" to "true" instead.
* "sessionAcknowledgeMode" set to "CLIENT_ACKNOWLEDGE":
* Automatic message acknowledgment after successful listener execution;
- * best-effort redelivery in case of exception thrown.
- * "sessionAcknowledgeMode" set to "DUPS_OK_ACKNOWLEDGE":
- * Lazy message acknowledgment during or after listener execution;
- * potential redelivery in case of exception thrown.
+ * best-effort redelivery in case of a user exception thrown as well as in case
+ * of other listener execution interruptions (such as the JVM dying).
* "sessionTransacted" set to "true":
* Transactional acknowledgment after successful listener execution;
- * guaranteed redelivery in case of exception thrown.
+ * guaranteed redelivery in case of a user exception thrown as well as
+ * in case of other listener execution interruptions (such as the JVM dying).
*
- * The exact behavior might vary according to the concrete listener container
- * and JMS provider used.
*
- * There are two solutions to the duplicate processing problem:
+ *
There are two solutions to the duplicate message processing problem:
*
* - Either add duplicate message detection to your listener, in the
* form of a business entity existence check or a protocol table check. This
* usually just needs to be done in case of the JMSRedelivered flag being
- * set on the incoming message (else just process straightforwardly).
- *
- Or wrap the entire processing with an XA transaction, covering the
- * reception of the message as well as the execution of the message listener.
- * This is only supported by {@link DefaultMessageListenerContainer}, through
- * specifying a "transactionManager" (typically a
+ * set on the incoming message (otherwise just process straightforwardly).
+ * Note that with "sessionTransacted" set to "true", duplicate messages will
+ * only appear in case of the JVM dying at the most unfortunate point possible
+ * (i.e. after your business logic executed but before the JMS part got committed),
+ * so duplicate message detection is just there to cover a corner case.
+ *
- Or wrap your entire processing with an XA transaction, covering the
+ * reception of the JMS message as well as the execution of the business logic in
+ * your message listener (including database operations etc). This is only
+ * supported by {@link DefaultMessageListenerContainer}, through specifying
+ * an external "transactionManager" (typically a
* {@link org.springframework.transaction.jta.JtaTransactionManager}, with
- * a corresponding XA-aware JMS {@link javax.jms.ConnectionFactory} passed in as
- * "connectionFactory").
+ * a corresponding XA-aware JMS {@link javax.jms.ConnectionFactory} passed in
+ * as "connectionFactory").
*
* Note that XA transaction coordination adds significant runtime overhead,
* so it might be feasible to avoid it unless absolutely necessary.
@@ -108,7 +119,7 @@ import org.springframework.util.ReflectionUtils;
* Alternatively, specify a
* {@link org.springframework.transaction.jta.JtaTransactionManager} as
* "transactionManager" for a fully XA-aware JMS provider - typically when
- * running on a J2EE server, but also for other environments with a JTA
+ * running on a Java EE server, but also for other environments with a JTA
* transaction manager present. This will give full "exactly-once" guarantees
* without custom duplicate message checks, at the price of additional
* runtime processing overhead.
@@ -889,7 +900,7 @@ public abstract class AbstractMessageListenerContainer extends AbstractJmsListen
if (errorHandler != null) {
errorHandler.handleError(ex);
}
- else if (logger.isWarnEnabled()) {
+ else {
logger.warn("Execution of JMS message listener failed, and no ErrorHandler has been set.", ex);
}
}
@@ -901,7 +912,6 @@ public abstract class AbstractMessageListenerContainer extends AbstractJmsListen
*/
@SuppressWarnings("serial")
private static class MessageRejectedWhileStoppingException extends RuntimeException {
-
}
}
diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/SimpleMessageListenerContainer.java b/spring-jms/src/main/java/org/springframework/jms/listener/SimpleMessageListenerContainer.java
index b5272f720bd..c784eb5a12f 100644
--- a/spring-jms/src/main/java/org/springframework/jms/listener/SimpleMessageListenerContainer.java
+++ b/spring-jms/src/main/java/org/springframework/jms/listener/SimpleMessageListenerContainer.java
@@ -47,7 +47,8 @@ import org.springframework.util.Assert;
* on acknowledge modes and transaction options. Note that this container
* exposes standard JMS behavior for the default "AUTO_ACKNOWLEDGE" mode:
* that is, automatic message acknowledgment after listener execution,
- * with redelivery in case of an exception thrown.
+ * with no redelivery in case of a user exception thrown but potential
+ * redelivery in case of the JVM dying during listener execution.
*
* For a different style of MessageListener handling, through looped
* {@code MessageConsumer.receive()} calls that also allow for