Spring JMS CLIENT_ACKNOWLEDGE

用Spring 的 JmsTemplate 来接收消息时, 按照其文档:

/*
Default settings for JMS Sessions are "not transacted" and "auto-acknowledge". As defined by the J2EE specification, the transaction and acknowledgement parameters are ignored when a JMS Session is created inside an active transaction, no matter if a JTA transaction or a Spring-managed transaction. To configure them for native JMS usage, specify appropriate values for the "sessionTransacted" and "sessionAcknowledgeMode" bean properties.
*/


按照JMS 规范, 如果是在事务内部接收消息, 会忽略sessionAcknowledgeMode 选项, Session.sessionAcknowledgeMode 总是 auto-acknowledge. 如果在事务外部调用,默认是 auto-acknowledge的, 如果需要定义为其他 acknowledge mode, 设置sessionTransacted 和sessionAcknowledgeMode属性. 但是, 当我设置sessionTransacted为false, sessionAcknowledgeMode为 client acknowledge 时, 如果调用消息的 acknowledge 方法, 会抛出异常, 因为每次接收完了消息, JmsTemplate 会将 Session 和 Connection 都关闭. 而且消息也是auto-acknowledge的.

查看JmsTemplate 的原代码,发现:
最终接收消息的代码会进入这个方法:
protected Message doReceive(Session session, MessageConsumer consumer)

这是个 protected 方法, subclass 可以 override 它.
于是跟踪进去看看里面的代码发现:

if (session.getTransacted()) {
// Commit necessary - but avoid commit call within a JTA transaction.
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this template -> commit.
JmsUtils.commitIfNecessary(session);
}
}
else if (isClientAcknowledge(session)) {
// Manually acknowledge message, if any.
if (message != null) {
message.acknowledge();
}
}


注意到这句: else if (isClientAcknowledge(session)) {

这就是在事务外部接收消息后的处理, 如果我们设置了Session 为 client acknowledge 模式, JmsTemplate 会在这里acknowledge 接收到的消息的.

刚好可以 override 这部分代码, 嵌入我们自己的处理, 让我们自己来决定是否 acknowledge 接收到的消息.

解决方法:
1)

public interface MessageHandler {

/**
* Process the message, if process finish successfully, return true, otherwise false
* return true if process successfully
*/
boolean processMessage(Message message);
}



2) Extend JmsTemplate, override JmsTemplate's method: protected Message doReceive(Session session, MessageConsumer consumer).


public class MyJmsTemplate extends JmsTemplate {
...
} else if (isClientAcknowledge(session)) {
// Manually acknowledge message if MessageHandler is not null and process message successfully
if (message != null) {
if (messageHandler == null || (messageHandler != null && messageHandler.processMessage(message)))
message.acknowledge();
}
}


3) Sample MessageHandler

public class SampleMessageHandler implements MessageHandler {

@Override
public boolean processMessage(Message message) {
try {
int flag = message.getIntProperty("flag");
return (flag < 2);
} catch (JMSException e) {
e.printStackTrace();
return false;
}
}

}


4) 测试时, 设置一下sssionTransacted 和 sssionAcknowledgeMode.

<bean id="myJmsTemplate" class="com.zero.demo.jms.MyJmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestination" ref="authReplyDestination"/>

<property name="sessionTransacted" value="false"/>
<property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE"/>
<property name="messageHandler">
<bean class="com.zero.demo.jms.SampleMessageHandler"/>
</property>
</bean>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值