ActiveMQ的消息确认问题

http://riddickbryant.iteye.com/blog/441890

【发送端】

session = connection.createSession(Boolean.FALSE,  Session.AUTO_ACKNOWLEDGE);

producer.setDeliveryMode(DeliveryMode.PERSISTENT);

 1 import javax.jms.*;
 2 import org.apache.activemq.ActiveMQConnection;
 3 import org.apache.activemq.ActiveMQConnectionFactory;
 4 /**
 5  *
 6  * @author LIN NP
 7  */
 8 public class JmsSender{
 9     
10   private ConnectionFactory connectionFactory = null;
11   private Connection connection = null;
12   private Session session = null;
13   private Destination destination = null;
14   private MessageProducer producer = null;
15   
16   private static final int SEND_NUMBER = 1;
17  
18   public void init()
19   {
20     // 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar
21     connectionFactory = new ActiveMQConnectionFactory(
22         ActiveMQConnection.DEFAULT_USER,
23         ActiveMQConnection.DEFAULT_PASSWORD,"tcp://localhost:61616");    // ActiveMQ默认使用的TCP连接端口是61616
24     
25     try{
26       // 构造从工厂得到连接对象
27       connection = connectionFactory.createConnection();
28       connection.start();
29       // 获取操作连接
30       session = connection.createSession(Boolean.FALSE,  Session.AUTO_ACKNOWLEDGE);
31       
32       //第一种方式:Queue
33       
34 //            destination = session.createQueue("xkey");        // "xkey"可以取其他的。
35 //            producer = session.createProducer(destination); // 得到消息生成者【发送者】
36       
37       //第二种方式:Topic
38        Topic topic = session.createTopic("xkey.Topic");
39        producer = session.createProducer(topic);
40 
41       // 持久化
42       producer.setDeliveryMode(DeliveryMode.PERSISTENT);
43       
44       // 构造消息,此处写死,项目就是参数,或者方法获取
45       sendMessage(session,producer);
46       
47       //session.commit();
48     }
49     catch(Exception e)
50     {
51       e.printStackTrace();
52     }
53     finally
54     {
55       try 
56       {
57         connection.close();
58       } 
59       catch (JMSException e) 
60       {
61         // TODO Auto-generated catch block
62         e.printStackTrace();
63       }
64     }
65   }
66   
67   
68   private void sendMessage(Session session,MessageProducer producer) throws JMSException
69   {
70     for (int i = 1; i <= SEND_NUMBER; i ++) 
71     {  
72       TextMessage message = session.createTextMessage("发送消息" + i);  
73       
74       System.out.println("发送消息" + i);  
75       
76    // 发送消息
77       producer.send(message);
78       
79     }  
80   }
81   /**
82    * @param args
83    */
84   public static void main(String[] args) 
85   {
86     // TODO Auto-generated method stub
87     JmsSender jms = new JmsSender();
88     jms.init();
89   }
90 }

 

【接收端】

connection = connectionFactory.createConnection();
connection.setClientID("bbb");
connection.start();

session = connection.createSession(Boolean.FALSE,  Session.AUTO_ACKNOWLEDGE); 

consumer = session.createDurableSubscriber(topic,"bbb"); //持久订阅

 1 import javax.jms.*;
 2 import org.apache.activemq.ActiveMQConnection;
 3 import org.apache.activemq.ActiveMQConnectionFactory;
 4 /**
 5  *
 6  * @author LIN NP
 7  */
 8 public class JmsReceiver
 9 {
10   private ConnectionFactory connectionFactory = null;
11   private Connection connection = null;
12   private Session session = null;
13   private MessageConsumer consumer = null;
14   private Destination destination = null;
15   public void init()
16   {
17     connectionFactory = new ActiveMQConnectionFactory(
18         ActiveMQConnection.DEFAULT_USER,
19         ActiveMQConnection.DEFAULT_PASSWORD,"tcp://localhost:61616"); // ActiveMQ默认使用的TCP连接端口是61616
20     try
21     {
22       // 构造从工厂得到连接对象
23       connection = connectionFactory.createConnection();
24       connection.setClientID("bbb"); 
25       connection.start();
26       // 获取操作连接
27       session = connection.createSession(Boolean.FALSE,  Session.AUTO_ACKNOWLEDGE); 
28       /**
29       * 第一种方式:Queue
30       */
31 //            destination = session.createQueue("xkey");
32 //            consumer = session.createConsumer(destination);
33       /**
34        * 第二种方式:Topic
35        */
36       
37       Topic topic = session.createTopic("xkey.Topic");
38       //consumer = session.createConsumer(topic);
39       consumer = session.createDurableSubscriber(topic,"bbb"); //持久订阅
40       
41       /**
42         * 
43         */
44       while (true) 
45       {  
46         //设置接收者接收消息的时间,为了便于测试,这里设定为500s
47         TextMessage message = (TextMessage) consumer.receive(500);  
48         if (null != message) 
49         {  
50           System.out.println("Receiver: " + message.getText());  
51         }
52         else 
53         {  
54           break;  
55         }  
56       }  
57     }
58     catch(Exception e)
59     {
60       e.printStackTrace();
61     }
62     finally
63     {
64       try 
65       {
66         connection.close();
67       } 
68       catch (JMSException e) 
69       {
70         // TODO Auto-generated catch block
71         e.printStackTrace();
72       }
73     }
74   }
75   /**
76    * @param args
77    */
78   public static void main(String[] args) 
79   {
80     // TODO Auto-generated method stub
81     JmsReceiver jms = new JmsReceiver();
82     jms.init();
83   }
84 }

 

 

 

 1 //创建JMS连接和会话
 2 ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);   
 3 connection = factory.createConnection();   
 4 connection.setClientID(Constant.JMS_CLIENT_ID);   
 5 session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
 6 // 创建消息发送主题和发送者
 7 Topic jmsSendTopic = session.createTopic(sendTopic);
 8 sendTopicProducer = session.createProducer(jmsSendTopic);
 9 sendTopicProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
10 sendTopicProducer.setTimeToLive(Message.DEFAULT_TIME_TO_LIVE);
11 // 创建消息接收主题和接收者
12 Topic jmsReceiveTopic = session.createTopic(receiveTopic);
13 receiveTopicConsumer = session.createDurableSubscriber(jmsReceiveTopic,Constant.JMS_SUBSCRIBE_NAME);
14 receiveTopicConsumer.setMessageListener(this);
15 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

 

 1 //创建JMS连接和会话
 2 ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);   
 3 connection = factory.createConnection();   
 4 connection.setClientID(Constant.JMS_CLIENT_ID);   
 5 session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
 6 // 创建消息发送主题和发送者
 7 Topic jmsSendTopic = session.createTopic(sendTopic);
 8 sendTopicProducer = session.createProducer(jmsSendTopic);
 9 sendTopicProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
10 sendTopicProducer.setTimeToLive(Message.DEFAULT_TIME_TO_LIVE);
11 // 创建消息接收主题和接收者
12 Topic jmsReceiveTopic = session.createTopic(receiveTopic);
13 receiveTopicConsumer = session.createDurableSubscriber(jmsReceiveTopic,Constant.JMS_SUBSCRIBE_NAME);
14 receiveTopicConsumer.setMessageListener(this);
15 connection.start();  

 

posted @ 2015-07-07 13:25  Uncle_Nucky  阅读(556)  评论(0编辑  收藏  举报