获得一个简单的 Spring JMS 客户端确认工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9095471/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 04:54:14  来源:igfitidea点击:

Getting a simple Spring JMS client acknowledge to work

springjmsactivemq

提问by Scotty OB

Just starting to get my head around getting JMS ActiveMQ Acknowledgementsworking in Spring. So far I have a consumer working perfectly, with the exception that when I don't acknowledge the message, it's still taken from the queue (I expect it to stay there or end in a dead letter queue).

刚刚开始考虑JMS ActiveMQ Acknowledgements在 Spring 工作。到目前为止,我有一个消费者工作得很好,除了当我不确认消息时,它仍然从队列中取出(我希望它留在那里或以死信队列结束)。

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd">

    <!-- A JMS connection factory for ActiveMQ -->
    <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"
    p:brokerURL="failover://(tcp://jms1:61616,tcp://jms2:61616)?randomize=false&amp;jms.redeliveryPolicy.maximumRedeliveries=5" />

    <!-- A POJO that implements the JMS message listener -->
    <bean id="simpleMessageListener" class="com.company.ConsumerClass" />

    <!-- A JMS namespace aware Spring configuration for the message listener container -->
    <jms:listener-container
            container-type="default"
            connection-factory="connectionFactory"
            acknowledge="client"
            concurrency="10-50"
            cache="consumer">
        <jms:listener destination="someQueue" ref="simpleMessageListener" method="onMessage" />
    </jms:listener-container>
</beans>

In the ConsumerClass, my simple consumer looks something like this:

在 ConsumerClass 中,我的简单消费者看起来像这样:

@Override public final void onMessage(Message message) {
    Object postedMessage = null;
    try {
        postedMessage = ((ObjectMessage) message).getObject();

        if (postedMessage.getClass() == SomeMessageType.class) {
            try {
                //Some logic here

                message.acknowledge();
                return; //Success Here
            } catch (MyException e) {
                logger.error("Could not process message, but as I didn't call acknowledge I expect it to end up in the dead message queue");
            }
        }
    } catch (JMSException e) {
        logger.error("Error occurred pulling Message from Queue", e);
    }

    //Also worth noting, if I throw new RuntimeException("Aww Noos"); here then it won't take it from the queue, but it won't get consumed (or end up as dead letter)...
}

采纳答案by Scotty OB

I found the answer at http://ourcraft.wordpress.com/2008/07/21/simple-jms-transaction-rollbacks-work/

我在http://ourcraft.wordpress.com/2008/07/21/simple-jms-transaction-rollbacks-work/找到了答案

It appears it works well if you change acknowledge="transacted" and make sure you throw new RuntimeException("Message could not be consumed. Roll back transaction"); at the end of the OnMessage() routine.

如果您更改acknowledge="transacted" 并确保抛出新的RuntimeException("Message could not be used. Roll back transaction"); 看起来效果很好。在 OnMessage() 例程的末尾。

Still no idea what acknowledge="client" achieves though

仍然不知道acknowledge="client" 实现了什么

回答by Tarun

Read this documentation: Spring JMS container does not use the message.acknowledge()

阅读此文档:Spring JMS 容器不使用 message.acknowledge()

The listener container offers the following message acknowledgment options:

侦听器容器提供以下消息确认选项:

"sessionAcknowledgeMode" set to "AUTO_ACKNOWLEDGE" (default): Automatic message acknowledgment before listener execution; no redelivery in case of exception thrown.
"sessionAcknowledgeMode" set to "CLIENT_ACKNOWLEDGE": Automatic message acknowledgment after successful listener execution; no 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.
"sessionTransacted" set to "true": Transactional acknowledgment after successful listener execution; guaranteed redelivery in case of exception thrown.

“sessionAcknowledgeMode”设置为“AUTO_ACKNOWLEDGE”(默认):监听器执行前自动确认消息;在抛出异常的情况下不重新发送。
“sessionAcknowledgeMode”设置为“CLIENT_ACKNOWLEDGE”:监听器执行成功后自动确认消息;在抛出异常的情况下不重新发送。
“sessionAcknowledgeMode”设置为“DUPS_OK_ACKNOWLEDGE”:监听器执行期间或之后的延迟消息确认;抛出异常时的潜在重新交付。
“sessionTransacted”设置为“true”:成功监听器执行后的事务确认;在抛出异常的情况下保证重新交付。

回答by gelin

Nowadays Spring provides good wrapper over plain JMSmessage listeners.

如今,Spring 为普通JMS消息侦听器提供了很好的包装器。

See JavaDocs of AbstractMessageListenerContainer.

请参阅AbstractMessageListenerContainer 的JavaDocs 。

"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 JVMdying).

"sessionAcknowledgeMode"设置为"CLIENT_ACKNOWLEDGE":成功侦听器执行后自动确认消息;在抛出用户异常以及其他侦听器执行中断(例如JVM死亡)的情况下,尽力重新传递。

So, when you define a @JmsListenermethod, the acknowledgement is sent automatically when it's completed successfully, but you can throw an exception to receive the message again.

因此,当您定义@JmsListener方法时,确认会在成功完成后自动发送,但您可以抛出异常以再次接收消息。

回答by Kaushik Lele

Call acknowledge() method on message in your consumer.

在您的消费者中对消息调用acknowledge() 方法。

Consider the following scenario: An application receives but does not acknowledge a message. The application receives a subsequent message and acknowledges it. What happens to the former message? The former message is also considered acknowledged. Generally, acknowledging a particular message acknowledges all prior messages the session receives. In the above output, only message 5 is explicitly acknowledged. All the messages before message 5 are implicitly acknowledged. Messages after message 5 are not acknowledged.

考虑以下场景:应用程序接收但不确认消息。应用程序接收后续消息并确认它。之前的消息会怎样?前一条消息也被视为已确认。通常,确认特定消息会确认会话接收到的所有先前消息。在上面的输出中,只有消息 5 被明确确认。消息 5 之前的所有消息都被隐式确认。消息 5 之后的消息不被确认。

For more details refer this article

有关更多详细信息,请参阅这篇文章

Also Check this article Sun Java System Message Queue 4.3 Developer's Guide for Java Clients

另请查看这篇文章Sun Java System Message Queue 4.3 Developer's Guide for Java Clients

回答by maximdim

In my practice client acknowledgement rarely if ever used. Typical setup is auto acknowledge so if your code returns from onMessage() normally (w/o exception) the message is automatically acknowledged. If your code throws exception from onMessage() there is no acknowledgement and message typically would be re-delivered up to pre-configured number of times, after which it would typically be discarded or put into dead message queue.

在我的实践中,客户确认很少使用。典型的设置是自动确认,因此如果您的代码从 onMessage() 正常返回(无异常),消息将自动确认。如果您的代码从 onMessage() 抛出异常,则不会有确认,并且消息通常会重新传递至预先配置的次数,之后通常会被丢弃或放入死消息队列。

In your case, from JMS server point of view, it looks like client asked for message but never acknowledged so it's still 'being processed' by the client. In such case message would be invisible for other consumers on the same Queue so you might get the impression that message was 'take off the queue' while as the matter of fact it's still there. Obviously you won't see such message in dead message queue either.

在您的情况下,从 JMS 服务器的角度来看,看起来客户端请求消息但从未确认过,因此它仍然由客户端“正在处理”。在这种情况下,消息对于同一队列上的其他消费者来说是不可见的,因此您可能会觉得消息“从队列中取出”,而事实上它仍然存在。显然你也不会在死消息队列中看到这样的消息。

I suggest you read JMS specification to get clear understanding of different acknowledgement modes.

我建议您阅读 JMS 规范以清楚了解不同的确认模式。

回答by Dipaktank

Use following code it will work.

使用以下代码它将起作用。

<bean id="{containerName}"  class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref={connectionFactoryBean} />
    <property name="destinationName" ref="{queue}" />
    <property name="messageListener" ref="{listner}" />
    <property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE"/>
</bean>