activemq 应答模式

来源:互联网 发布:apache配置目录访问 编辑:程序博客网 时间:2024/05/20 06:51

http://greemranqq.iteye.com/blog/2194051


一、序言

       JMS 用于系统解耦有一定帮助,像我们 iteye 的一些系统消息,可能非重要要消息,就没那么严格的限制,统一异步发送就行了,反正上线你就能看到。有些情况下我们需要消息两端进行确认,比如一些比较重要的金额之类的信息。

 

二、实例场景

       我们ERP系统中的财务模块是分开的,当成一个单独的财务系统,那么从ERP那么那送的财务信息,或者财务系统接收了,需要给ERP 那边一个确认信息,不然消息没处理成功或者其他异常,导致金额数据出问题,这个麻烦比较大的。

 

三、JMS 场景对应

       场景一:

       1.Producer  -----> 发送消息到broker

       2.Customer------> 从broker 收到消息

       3.Customer------> 向broker 确认消息收到

      

       对于场景一,可能没有完全满足我么你的实例场景,但是可以通过broker 获得,也算是一种异步通知,下面来看看对应的伪代码:

       场景1.1 :开启事务的情况,是根据session 的commit 和 rollback 进行处理确认消息

       

Java代码  收藏代码
  1. // 这是我们消息生产者伪代码,初始化过程这里暂时不贴了,参考前面的  
  2. // true : 表示开启事务,开启事务,必须的commit  
  3. Session session =  InitJms.connection.createSession(true,Session.AUTO_ACKNOWLEDGE);  
  4.         // 创建一个文本消息  
  5.        TextMessage message =  session.createTextMessage("测试消息");  
  6.         // 创建发送消息目的地  
  7.        Destination send_destination = session.createQueue("order_queue");  
  8.         // 生产者  
  9.        MessageProducer producer = session.createProducer(send_destination);  
  10.        // 发送  
  11.        producer.send(message);  
  12.        // 这里必须提交,因为开启了事务,不然broker 里面是看不到消息的  
  13.        session.commit();  

   

Java代码  收藏代码
  1. // 这是消费者代码,同样用true  
  2.         Session session =  InitJms.connection.createSession(true,Session.CLIENT_ACKNOWLEDGE);  
  3.         // 指定接收消息的地方  
  4.         Destination destination = session.createQueue("order_queue");  
  5.         // 创建消费者  
  6.         MessageConsumer consumer = session.createConsumer(destination);  
  7.         try {  
  8.             // 接收消息  
  9.             TextMessage message = (TextMessage)consumer.receive(1000);  
  10.             System.out.println(message.getText());    
  11.             // 收到消息之后进行确认      
  12.             session.commit();  
  13.         }finally {  
  14.             session.close();  
  15.             InitJms.connection.close();  
  16.         }  

 

 

     注意,上面由于没用messageListener 而且关闭了连接,因此控制台看不到消费者存在了:

     

      场景1.2 我们自动响应服务器 和 非事务,客户端响应服务器的情况

       

Java代码  收藏代码
  1.  // 消费端 在这里默认 采用AUTO 就会自动响应了  
  2. Session session =  InitJms.connection.createSession(false,Session.AUTO_ACKNOWLEDGE);  
  3.   
  4. // 同理,如果设置   
  5. InitJms.connection.createSession(false,Session.CLIENT_ACKNOWLEDGE);  
  6. // 就需要手动响应  
  7. message.acknowledge();  

 

    注意:如果没有按要求响应broker,消费端还是能拿到消息的,而且能重复拿到,5.11的版本可以拿到7次,可以通过下面的检查一些信息:

    

Java代码  收藏代码
  1. // 是否收到过消息,第一次fasle,第二次开始就是true  
  2. message.getJMSRedelivered();  
  3. // 消息发送时间:毫秒  
  4. message.getJMSTimestamp();  
  5. // 从broker 重复获取消息的次数,5.11最多6次。  
  6. // 参考 RedeliveryPolicy  DEFAULT_MAXIMUM_REDELIVERIES 可以更改  
  7. message.getStringProperty("JMSXDeliveryCount")  
  8. // 消息存活时间:0 一直存在  
  9. message.getJMSExpiration();  
  10.   
  11. 当然还有很多,可以参考官方文档:  
  12. http://activemq.apache.org/activemq-message-properties.html  
  13. 以及  
  14. http://activemq.apache.org/features.html  

 

四、双向应答的场景:

     双向应答可以这样描述

     1.producer-->发送消息到broker, 然后等待确认消息

     2.customer-->从broker 获得消息,然后发送确认消息--->broker

     3.producer --> 从broker 获得确认消息

 

     举个栗子:张三写封信送到邮局中转站,然后李四从中转站获得信,然后在写一份回执信,放到中转站,然后张三去取,当然张三写信的时候就得写明回信地址,看代码

      

Java代码  收藏代码
  1. // 承接刚才的代码,发送消息的时候,需要填写一个回执的地址  
  2.       Destination recall_destination = session.createQueue("recall_queue");  
  3.       // 将回执地址写在消息里面,方便李四知道  
  4.       message.setJMSReplyTo(recall_destination);  
  5.       producer.send(message);   
  6.          
  7.       // 发送之后,某个地方这里变成消息消费者,等待那边给我发送确认消息  
  8.       MessageConsumer replyConsumer =session.createConsumer(recall_destination);  
  9.        // 这里我们用个消息监听  
  10.        replyConsumer.setMessageListener(new MessageListener() {  
  11.            @Override  
  12.            public void onMessage(Message message) {  
  13.                TextMessage textMessage = (TextMessage) message;  
  14.                try {  
  15.                    System.out.println(textMessage.getText());  
  16.                } catch (JMSException e) {  
  17.                    e.printStackTrace();  
  18.                }  
  19.            }  
  20.        });  
 

 

    消费者:

    

Java代码  收藏代码
  1. // 获得回执地址  
  2.         Destination recall_destination = message.getJMSReplyTo();  
  3.         // 创建回执消息  
  4.         TextMessage textMessage = session.createTextMessage("张三,我已经收到消息了");  
  5.         // 以上收到消息之后,从新创建生产者,然后在回执过去  
  6.         MessageProducer producer = session.createProducer(recall_destination);  
  7.         producer.send(textMessage);  
 

 

    OK,这样就能相互通信了,你可以理解为通过两个通道进行的。

    注意:这种方式毕竟会慢一些了,除非有及时性的,需要两端处理另外的事情,才这么多,因为涉及2步,都会有类似于“拜占庭将军问题”,因此解决还需要 持久化、多点部署,反而麻烦,按前面的场景还好。

 

小结:

        1.这里大概介绍了activemq 的一些应答的及时,关于有些属性可以参考文档,具体问题具体分析~。~脱离场景谈性能都是耍流氓,这里也不会介绍性能问题,有测试的朋友可以告知一声。

        2.如果有问题的,请大家指出,非常感谢。


0 0
原创粉丝点击