31
31
import org .springframework .util .ErrorHandler ;
32
32
33
33
/**
34
- * Abstract base class for message listener containers. Can either host
35
- * a standard JMS {@link javax.jms.MessageListener} or a Spring-specific
36
- * {@link SessionAwareMessageListener}.
34
+ * Abstract base class for Spring message listener container implementations.
35
+ * Can either host a standard JMS {@link javax.jms.MessageListener} or Spring's
36
+ * {@link SessionAwareMessageListener} for actual message processing .
37
37
*
38
- * <p>Usually holds a single JMS {@link Connection} that all listeners are
39
- * supposed to be registered on, which is the standard JMS way of managing
40
- * listeners. Can alternatively also be used with a fresh Connection per
41
- * listener, for J2EE- style XA-aware JMS messaging. The actual registration
42
- * process is up to concrete subclasses.
38
+ * <p>Usually holds a single JMS {@link Connection} that all listeners are supposed
39
+ * to be registered on, which is the standard JMS way of managing listener sessions.
40
+ * Can alternatively also be used with a fresh Connection per listener, for Java EE
41
+ * style XA-aware JMS messaging. The actual registration process is up to concrete
42
+ * subclasses.
43
43
*
44
- * <p><b>NOTE:</b> The default behavior of this message listener container
45
- * is to <b>never</b> propagate an exception thrown by a message listener up to
46
- * the JMS provider. Instead, it will log any such exception at the error level.
44
+ * <p><b>NOTE:</b> The default behavior of this message listener container is to
45
+ * <b>never</b> propagate an exception thrown by a message listener up to the JMS
46
+ * provider. Instead, it will log any such exception at the error level.
47
47
* This means that from the perspective of the attendant JMS provider no such
48
48
* listener will ever fail. However, if error handling is necessary, then
49
49
* any implementation of the {@link ErrorHandler} strategy may be provided to
56
56
* <li>"sessionAcknowledgeMode" set to "AUTO_ACKNOWLEDGE" (default):
57
57
* This mode is container-dependent: For {@link DefaultMessageListenerContainer},
58
58
* it means automatic message acknowledgment <i>before</i> listener execution, with
59
- * no redelivery in case of an exception. For {@link SimpleMessageListenerContainer},
59
+ * no redelivery in case of an exception and no redelivery in case of other listener
60
+ * execution interruptions either. For {@link SimpleMessageListenerContainer},
60
61
* it means automatic message acknowledgment <i>after</i> listener execution, with
61
- * redelivery in case of an exception thrown, as defined by the JMS specification.
62
- * In order to consistently achieve the latter behavior with any container variant,
63
- * consider setting "sessionTransacted" to "true" instead.
62
+ * no redelivery in case of a user exception thrown but potential redelivery in case
63
+ * of the JVM dying during listener execution. In order to consistently arrange for
64
+ * redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or -
65
+ * preferably - setting "sessionTransacted" to "true" instead.
66
+ * <li>"sessionAcknowledgeMode" set to "DUPS_OK_ACKNOWLEDGE":
67
+ * <i>Lazy</i> message acknowledgment during ({@link DefaultMessageListenerContainer})
68
+ * or shortly after ({@link SimpleMessageListenerContainer}) listener execution;
69
+ * no redelivery in case of a user exception thrown but potential redelivery in case
70
+ * of the JVM dying during listener execution. In order to consistently arrange for
71
+ * redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or -
72
+ * preferably - setting "sessionTransacted" to "true" instead.
64
73
* <li>"sessionAcknowledgeMode" set to "CLIENT_ACKNOWLEDGE":
65
74
* Automatic message acknowledgment <i>after</i> successful listener execution;
66
- * best-effort redelivery in case of exception thrown.
67
- * <li>"sessionAcknowledgeMode" set to "DUPS_OK_ACKNOWLEDGE":
68
- * <i>Lazy</i> message acknowledgment during or after listener execution;
69
- * <i>potential redelivery</i> in case of exception thrown.
75
+ * best-effort redelivery in case of a user exception thrown as well as in case
76
+ * of other listener execution interruptions (such as the JVM dying).
70
77
* <li>"sessionTransacted" set to "true":
71
78
* Transactional acknowledgment after successful listener execution;
72
- * <i>guaranteed redelivery</i> in case of exception thrown.
79
+ * <i>guaranteed redelivery</i> in case of a user exception thrown as well as
80
+ * in case of other listener execution interruptions (such as the JVM dying).
73
81
* </ul>
74
- * The exact behavior might vary according to the concrete listener container
75
- * and JMS provider used.
76
82
*
77
- * <p>There are two solutions to the duplicate processing problem:
83
+ * <p>There are two solutions to the duplicate message processing problem:
78
84
* <ul>
79
85
* <li>Either add <i>duplicate message detection</i> to your listener, in the
80
86
* form of a business entity existence check or a protocol table check. This
81
87
* usually just needs to be done in case of the JMSRedelivered flag being
82
- * set on the incoming message (else just process straightforwardly).
83
- * <li>Or wrap the <i>entire processing with an XA transaction</i>, covering the
84
- * reception of the message as well as the execution of the message listener.
85
- * This is only supported by {@link DefaultMessageListenerContainer}, through
86
- * specifying a "transactionManager" (typically a
88
+ * set on the incoming message (otherwise just process straightforwardly).
89
+ * Note that with "sessionTransacted" set to "true", duplicate messages will
90
+ * only appear in case of the JVM dying at the most unfortunate point possible
91
+ * (i.e. after your business logic executed but before the JMS part got committed),
92
+ * so duplicate message detection is just there to cover a corner case.
93
+ * <li>Or wrap your <i>entire processing with an XA transaction</i>, covering the
94
+ * reception of the JMS message as well as the execution of the business logic in
95
+ * your message listener (including database operations etc). This is only
96
+ * supported by {@link DefaultMessageListenerContainer}, through specifying
97
+ * an external "transactionManager" (typically a
87
98
* {@link org.springframework.transaction.jta.JtaTransactionManager}, with
88
- * a corresponding XA-aware JMS {@link javax.jms.ConnectionFactory} passed in as
89
- * "connectionFactory").
99
+ * a corresponding XA-aware JMS {@link javax.jms.ConnectionFactory} passed in
100
+ * as "connectionFactory").
90
101
* </ul>
91
102
* Note that XA transaction coordination adds significant runtime overhead,
92
103
* so it might be feasible to avoid it unless absolutely necessary.
102
113
* <li>Alternatively, specify a
103
114
* {@link org.springframework.transaction.jta.JtaTransactionManager} as
104
115
* "transactionManager" for a fully XA-aware JMS provider - typically when
105
- * running on a J2EE server, but also for other environments with a JTA
116
+ * running on a Java EE server, but also for other environments with a JTA
106
117
* transaction manager present. This will give full "exactly-once" guarantees
107
118
* without custom duplicate message checks, at the price of additional
108
119
* runtime processing overhead.
@@ -709,7 +720,7 @@ protected void invokeErrorHandler(Throwable ex) {
709
720
if (this .errorHandler != null ) {
710
721
this .errorHandler .handleError (ex );
711
722
}
712
- else if ( logger . isWarnEnabled ()) {
723
+ else {
713
724
logger .warn ("Execution of JMS message listener failed, and no ErrorHandler has been set." , ex );
714
725
}
715
726
}
@@ -721,7 +732,6 @@ else if (logger.isWarnEnabled()) {
721
732
*/
722
733
@ SuppressWarnings ("serial" )
723
734
private static class MessageRejectedWhileStoppingException extends RuntimeException {
724
-
725
735
}
726
736
727
737
}
0 commit comments