类 AbstractMessageListenerContainer

  • 所有已实现的接口:
    Aware, BeanNameAware, DisposableBean, InitializingBean, Lifecycle, Phased, SmartLifecycle, MessageListenerContainer
    直接已知子类:
    AbstractPollingMessageListenerContainer, SimpleMessageListenerContainer

    public abstract class AbstractMessageListenerContainer
    extends AbstractJmsListeningContainer
    implements MessageListenerContainer
    Abstract base class for Spring message listener container implementations. Can either host a standard JMS MessageListener or Spring's SessionAwareMessageListener for actual message processing.

    Usually holds a single JMS 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. 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 ErrorHandler strategy may be provided to the setErrorHandler(ErrorHandler) method. Note that JMSExceptions will be passed to the ErrorHandler in addition to (but after) being passed to an ExceptionListener, if one has been provided.

    The listener container offers the following message acknowledgment options:

    • "sessionAcknowledgeMode" set to "AUTO_ACKNOWLEDGE" (default): This mode is container-dependent: For DefaultMessageListenerContainer, it means automatic message acknowledgment before listener execution, with no redelivery in case of an exception and no redelivery in case of other listener execution interruptions either. For SimpleMessageListenerContainer, it means automatic message acknowledgment after listener execution, with 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 (DefaultMessageListenerContainer) or shortly after (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 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 a user exception thrown as well as in case of other listener execution interruptions (such as the JVM dying).

    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 (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 DefaultMessageListenerContainer, through specifying an external "transactionManager" (typically a JtaTransactionManager, with a corresponding XA-aware 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.

    Recommendations:

    • The general recommendation is to set "sessionTransacted" to "true", typically in combination with local database transactions triggered by the listener implementation, through Spring's standard transaction facilities. This will work nicely in Tomcat or in a standalone environment, often combined with custom duplicate message detection (if it is unacceptable to ever process the same message twice).
    • Alternatively, specify a JtaTransactionManager as "transactionManager" for a fully XA-aware JMS provider - typically when 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.

    Note that the "sessionTransacted" flag is strongly recommended over JmsTransactionManager, provided that transactions do not need to be managed externally. As a consequence, set the transaction manager only if you are using JTA or if you need to synchronize with custom external transaction arrangements.

    从以下版本开始:
    2.0
    作者:
    Juergen Hoeller, Stephane Nicoll
    另请参阅:
    setMessageListener(java.lang.Object), MessageListener, SessionAwareMessageListener, handleListenerException(java.lang.Throwable), DefaultMessageListenerContainer, SimpleMessageListenerContainer, JmsMessageEndpointManager