刚刚开始让我的目标让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&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>
在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)...
}
答案 0 :(得分:18)
阅读本文档:Spring JMS容器不使用message.acknowledge()
侦听器容器提供以下消息确认选项:
“sessionAcknowledgeMode”设置为“AUTO_ACKNOWLEDGE”(默认值):在侦听器执行之前自动确认消息;如果抛出异常,则不予以重新发送 “sessionAcknowledgeMode”设置为“CLIENT_ACKNOWLEDGE”:成功侦听器执行后自动确认消息;如果抛出异常,则不予以重新发送 “sessionAcknowledgeMode”设置为“DUPS_OK_ACKNOWLEDGE”:在侦听器执行期间或之后的延迟消息确认;如果抛出异常,可能会重新发送 “sessionTransacted”设置为“true”:成功监听器执行后的事务确认;在发生例外的情况下保证重新发送。
答案 1 :(得分:7)
我在http://ourcraft.wordpress.com/2008/07/21/simple-jms-transaction-rollbacks-work/
找到答案如果你更改acknowledge =“transacted”并确保你抛出新的RuntimeException(“消息无法消耗。回滚事务”),它似乎运行良好;在OnMessage()例程的末尾。
仍然不知道承认=“客户”实现了什么
答案 2 :(得分:5)
现在Spring提供了对普通JMS
消息监听器的良好包装。
参见AbstractMessageListenerContainer的JavaDocs。
"sessionAcknowledgeMode"
设置为"CLIENT_ACKNOWLEDGE"
:成功侦听器执行后自动确认消息;在抛出用户异常的情况下以及在其他侦听器执行中断的情况下(例如JVM
死亡),尽力而为重新传递。
因此,当您定义@JmsListener方法时,确认会在成功完成后自动发送,但您可以抛出异常以再次接收消息。
答案 3 :(得分:-1)
在我的实践中,客户确认很少使用。典型设置是自动确认,因此如果您的代码通常从onMessage()返回(没有异常),则会自动确认消息。如果您的代码从onMessage()抛出异常,则无法确认,并且通常会将消息重新传递到预先配置的次数,之后通常会将其丢弃或放入死信息队列中。
在您的情况下,从JMS服务器的角度来看,它看起来像客户端要求消息但从未确认,因此它仍然由客户端“处理”。在这种情况下,消息对于同一队列中的其他消费者是不可见的,因此您可能会得到消息“脱离队列”的印象,而事实上它仍然存在。显然,你也不会在死信息队列中看到这样的消息。
我建议你阅读JMS规范,以便清楚地了解不同的确认模式。
答案 4 :(得分:-1)
在您的消费者中对消息调用acknowledge()方法。
请考虑以下情形:应用程序接收但不确认消息。应用程序收到后续消息并对其进行确认。前一条消息怎么了?前一条消息也被认为是公认的。通常,确认特定消息会确认会话接收的所有先前消息。在上面的输出中,只显示消息5。消息5之前的所有消息都被隐式确认。消息5之后的消息未得到确认。
有关详细信息,请参阅this article
另请参阅此文章Sun Java System Message Queue 4.3 Developer's Guide for Java Clients
答案 5 :(得分:-2)
使用以下代码。
<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>