ActiveMQ的消息确认问题
http://riddickbryant.iteye.com/blog/441890
【发送端】
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
import javax.jms.*;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
*
* @author LIN NP
*/
public class JmsSender{ private ConnectionFactory connectionFactory = null;
private Connection connection = null;
private Session session = null;
private Destination destination = null;
private MessageProducer producer = null; private static final int SEND_NUMBER = 1; public void init()
{
// 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,"tcp://localhost:61616"); // ActiveMQ默认使用的TCP连接端口是61616 try{
// 构造从工厂得到连接对象
connection = connectionFactory.createConnection();
connection.start();
// 获取操作连接
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); //第一种方式:Queue // destination = session.createQueue("xkey"); // "xkey"可以取其他的。
// producer = session.createProducer(destination); // 得到消息生成者【发送者】 //第二种方式:Topic
Topic topic = session.createTopic("xkey.Topic");
producer = session.createProducer(topic); // 持久化
producer.setDeliveryMode(DeliveryMode.PERSISTENT); // 构造消息,此处写死,项目就是参数,或者方法获取
sendMessage(session,producer); //session.commit();
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
try
{
connection.close();
}
catch (JMSException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} private void sendMessage(Session session,MessageProducer producer) throws JMSException
{
for (int i = 1; i <= SEND_NUMBER; i ++)
{
TextMessage message = session.createTextMessage("发送消息" + i); System.out.println("发送消息" + i); // 发送消息
producer.send(message); }
}
/**
* @param args
*/
public static void main(String[] args)
{
// TODO Auto-generated method stub
JmsSender jms = new JmsSender();
jms.init();
}
}
【接收端】
connection = connectionFactory.createConnection();
connection.setClientID("bbb");
connection.start();
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
consumer = session.createDurableSubscriber(topic,"bbb"); //持久订阅
import javax.jms.*;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
*
* @author LIN NP
*/
public class JmsReceiver
{
private ConnectionFactory connectionFactory = null;
private Connection connection = null;
private Session session = null;
private MessageConsumer consumer = null;
private Destination destination = null;
public void init()
{
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,"tcp://localhost:61616"); // ActiveMQ默认使用的TCP连接端口是61616
try
{
// 构造从工厂得到连接对象
connection = connectionFactory.createConnection();
connection.setClientID("bbb");
connection.start();
// 获取操作连接
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
/**
* 第一种方式:Queue
*/
// destination = session.createQueue("xkey");
// consumer = session.createConsumer(destination);
/**
* 第二种方式:Topic
*/ Topic topic = session.createTopic("xkey.Topic");
//consumer = session.createConsumer(topic);
consumer = session.createDurableSubscriber(topic,"bbb"); //持久订阅 /**
*
*/
while (true)
{
//设置接收者接收消息的时间,为了便于测试,这里设定为500s
TextMessage message = (TextMessage) consumer.receive(500);
if (null != message)
{
System.out.println("Receiver: " + message.getText());
}
else
{
break;
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
try
{
connection.close();
}
catch (JMSException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* @param args
*/
public static void main(String[] args)
{
// TODO Auto-generated method stub
JmsReceiver jms = new JmsReceiver();
jms.init();
}
}
//创建JMS连接和会话
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);
connection = factory.createConnection();
connection.setClientID(Constant.JMS_CLIENT_ID);
session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
// 创建消息发送主题和发送者
Topic jmsSendTopic = session.createTopic(sendTopic);
sendTopicProducer = session.createProducer(jmsSendTopic);
sendTopicProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
sendTopicProducer.setTimeToLive(Message.DEFAULT_TIME_TO_LIVE);
// 创建消息接收主题和接收者
Topic jmsReceiveTopic = session.createTopic(receiveTopic);
receiveTopicConsumer = session.createDurableSubscriber(jmsReceiveTopic,Constant.JMS_SUBSCRIBE_NAME);
receiveTopicConsumer.setMessageListener(this);
connection.start();
解答:问题原因在于这段代码在接收到JMS消息时不会向ActiveMQ服务器确认消息的接收,故而ActiveMQ服务器一直认为该消息没有成功发送给接收者,因而每次接收者重启之后就会收到ActiveMQ服务器发送过来的消息。在这里要解释一下session的创建。
session = connection.createSession(true,Session.Auto_ACKNOWLEDGE);
当createSession第一个参数为true时,表示创建的session被标记为transactional的,确认消息就通过确认和校正来自动地处理,第二个参数应该是没用的。
当createSession的第一个参数为false时,表示创建的session没有标记为transactional,此时有三种用于消息确认的选项:
**AUTO_ACKNOWLEDGE session将自动地确认收到的一则消息;
**CLIENT_ACKNOWLEDGE 客户端程序将确认收到的一则消息,调用这则消息的确认方法;
**DUPS_OK_ACKNOWLEDGE 这个选项命令session“懒散的”确认消息传递,可以想到,这将导致消息提供者传递的一些复制消息可能出错。
JMS有两种消息传递方式。标记为NON_PERSISTENT的消息最多传递一次,而标记为PERSISTENT的消息将使用暂存后再转发的机理投递。如果一个JMS服务离线,那么持久性消息不会丢失,但是得等到这个服务恢复联机的时候才会被传递。所以默认的消息传递方式是非持久性的,虽然使用非持久性消息可能降低内存和需要的存储器,但这种传递方式只有当你不需要接收所有消息时才使用。
因此正确的代码只需改动一处就行了,即将true改为false
//创建JMS连接和会话
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);
connection = factory.createConnection();
connection.setClientID(Constant.JMS_CLIENT_ID);
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 创建消息发送主题和发送者
Topic jmsSendTopic = session.createTopic(sendTopic);
sendTopicProducer = session.createProducer(jmsSendTopic);
sendTopicProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
sendTopicProducer.setTimeToLive(Message.DEFAULT_TIME_TO_LIVE);
// 创建消息接收主题和接收者
Topic jmsReceiveTopic = session.createTopic(receiveTopic);
receiveTopicConsumer = session.createDurableSubscriber(jmsReceiveTopic,Constant.JMS_SUBSCRIBE_NAME);
receiveTopicConsumer.setMessageListener(this);
connection.start();
ActiveMQ的消息确认问题的更多相关文章
- activemq的消息确认机制ACK
一.简介 消息消费者有没有接收到消息,需要有一种机制让消息提供者知道,这个机制就是消息确认机制. ACK(Acknowledgement)即确认字符,在数据通信中,接收站发给发送站的一种传输类控制字符 ...
- Activemq消息确认机制 --转载
转自:http://blog.csdn.net/czp11210/article/details/47022639 ActiveMQ消息传送机制以及ACK机制详解 AcitveMQ是作为一种消息存 ...
- ActiveMQ发消息和收消息
来自:http://blog.163.com/chengwei_1104/blog/static/53645274201382315625329/ ActiveMQ 是Apache出品,最流行的,能力 ...
- JAVA消息确认机制之ACK模式
JMS API中约定了Client端可以使用四种ACK模式,在javax.jms.Session接口中: AUTO_ACKNOWLEDGE = 1 自动确认 CLIENT_ACKNOWLEDGE ...
- RabbitMQ 消息确认机制
消息确认机制 在之前异常处理部分就已经写了,对于consumer的异常退出导致消息丢失,可以时候consumer的消息确认机制.重复的就不说了,这里说一些不一样的. consumer的消息确认机制 当 ...
- (转)RabbitMQ消息队列(九):Publisher的消息确认机制
在前面的文章中提到了queue和consumer之间的消息确认机制:通过设置ack.那么Publisher能不到知道他post的Message有没有到达queue,甚至更近一步,是否被某个Consum ...
- ActiveMQ之消息指针
消息指针(Message cursor)是activeMQ里一个非常重要的核心类,它是提供某种优化消息存储的方法.消息中间件的实现一般都是当消费者准备好消费消息的时候,它会从持久化存储中一批一批的读取 ...
- JMS - 消息确认
消息确认机制 消息确认协议是保证消息传送的关键所在,同时,支持确认也是 JMS API 语义的要求.以下将分别从消息生产者.消息服务器.消息消费者的角度,来考察消息确认机制. 从消息生产者的角度考察 ...
- RabbitMQ消息队列(九):Publisher的消息确认机制
在前面的文章中提到了queue和consumer之间的消息确认机制:通过设置ack.那么Publisher能不到知道他post的Message有没有到达queue,甚至更近一步,是否被某个Consum ...
随机推荐
- java线程join的意思(转自http://zjj1211.blog_51cto_com)
Join,单词本事就是连接的意思. 先贴出几段代码猜猜结果. <1> public static int Main() { Alpha oAlpha = new Alpha(); Thre ...
- dede 去power by dedecms
include/dedesql.class.php 下的$arrs1和$arrs2的全注释掉
- (七)7.2 应用机器学习方法的技巧,准确率,召回率与 F值
建立模型 当使用机器学习的方法来解决问题时,比如垃圾邮件分类等,一般的步骤是这样的: 1)从一个简单的算法入手这样可以很快的实现这个算法,并且可以在交叉验证集上进行测试: 2)画学习曲线以决定是否更多 ...
- ORACLE 中KILL session
我们知道,在Oracle数据库中,可以通过kill session的方式来终止一个进程,其基本语法结构为: alter system kill session 'sid,serial#' ; 被kil ...
- Android下实现win8的按钮点击效果
原理就是自定义一个imageButton,实现动画效果 demo源码下载地址: 请戳这里----------------> 关于回弹张力的效果扩展,可以参考Facebook的开源动画库rebo ...
- Java循环语句之 for
Java 的循环结构中除了 while 和 do...while 外,还有 for 循环,三种循环可以相互替换. 语法: 执行过程: <1>. 执行循环变量初始化部分,设置循环的初始状态, ...
- IOS公司开发者账号申请详细教程
谈到苹果开发者账号,我们需要区分一下个人账号.公司账号和企业账号这三种,还有一种是教育账号,这个就不多说了. 个人账号:个人申请用于开发苹果app所使用的账号,仅限于个人使用,申请比较容易,$99. ...
- FZU 2171(线段树的延迟标记)
题意:容易理解. 分析:时隔很久,再一次写了一道线段树的代码,之前线段树的题也做了不少,包括各种延迟标记,但是在组队分任务之后,我们队的线段树就交给了另外一个队友在搞, 然后我就一直没去碰线段树的题了 ...
- Android百度地图开发(五)公交线路详情搜索、多条线路显示
一.公交线路详情检索 获取公交线路的详情主要分来两步,1.获取公交线路的Uid,2.通过Uid获取公交线路详情. 1.获取公交线路的Uid: /* * 获得公交线路图的Uid,并且根据系Uid发起公交 ...
- 一个c++剧情脚本指令系统
项目希望能够实现一些剧情动画,类似角色移动,镜头变化,台词展现等.剧情动画这东西随时需要修改调整,不能写死在代码里.考虑之后认为需要做一个简单的DSL来定制剧情脚本,策划在脚本里按顺序写入命令,然后我 ...