RabbitMQ使用场景练习:延迟队列(八)

  • 延时队列
     在实际业务场景中可能会用到延时消息发送,例如支付场景,准时支付、超过未支付将执行不同的方案,其中超时未支付可以看做一个延时消息。 
     RabbitMQ本身不具有延时消息队列的功能,但是可以通过TTL(Time To Live)、DLX(Dead Letter Exchanges)特性实现。其原理给消息设置过期时间,在消息队列上为过期消息指定转发器,这样消息过期后会转发到与指定转发器匹配的队列上,变向实现延时队列。利用RabbitMQ的这种特性,应该可以实现很多现实中的业务,我们可以发挥想象。 
      rabbitmq-delayed-message-exchange ,我们也可以使用插件来实现延时队列。利用TTL、DLX实现的延时队列可以中断,使用插件实现的延时队列是否可以中断?留着下次。。。 

  • 注意要点

为每一条消息设置过期时间
Java代码   收藏代码
  1. Builder properties=new BasicProperties.Builder();  
  2. //指定消息过期时间为12秒,队列上也可以指定消息的过期时间,两者以较小时间为准  
  3. properties.expiration("12000");//延时12秒,不会及时删除(在consuemr消费时判定是否过期,因为每条消息的过期时间不一致,删除过期消息就需要扫描整个队列)  
  4. channel.basicPublish("header_exchange""" ,properties.build(), SerializationUtils.serialize(object));  

在队列上设置队列过期时间(可以不用设置)、消息过期时间、过期消息转发规则
Java代码   收藏代码
  1. //设置消息过期时间为12秒,消息过期转发给指定转发器、匹配的routingkey(可不指定)  
  2. Map<String, Object> args=new HashMap<String, Object>();  
  3. args.put("x-expires"30000);//队列过期时间  
  4. args.put("x-message-ttl"12000);//队列上消息过期时间,应小于队列过期时间  
  5. args.put("x-dead-letter-exchange""exchange-direct");//过期消息转向路由  
  6. args.put("x-dead-letter-routing-key""routing-delay");//过期消息转向路由相匹配routingkey  

消息没有consumer消费才会过期,所以接收消息类中consumer需要注释掉  

队列上设置消息过期时间和消息上设置消息过期时间,优先级以较小的为准  

队列上设置消息过期时间和消息上设置消息过期时间,后者过期消息有可能不会及时删除,因为每条消息的过期时间不一致,删除过期消息就需要扫描整个队列,因此消费时判断是否过期  

  • 发送消息类

Java代码   收藏代码
  1. package com.demo.mq.rabbitmq.example08;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.Serializable;  
  5. import java.util.HashMap;  
  6. import java.util.Map;  
  7.   
  8. import org.apache.commons.lang3.SerializationUtils;  
  9.   
  10. import com.demo.mq.rabbitmq.MqManager;  
  11. import com.rabbitmq.client.AMQP.BasicProperties;  
  12. import com.rabbitmq.client.AMQP.BasicProperties.Builder;  
  13. import com.rabbitmq.client.BuiltinExchangeType;  
  14. import com.rabbitmq.client.Channel;  
  15. import com.rabbitmq.client.Connection;  
  16.   
  17. /** 
  18.  * 发送消息类 
  19.  * @author sheungxin 
  20.  * 
  21.  */  
  22. public class Send{  
  23.   
  24.     /** 
  25.      * 在topic转发器的基础上练习延时转发,发送消息时指定消息过期时间 
  26.      * 消息已发送到queue上,但未有consumer进行消费 
  27.      * @param object 消息主体 
  28.      * @throws IOException 
  29.      */  
  30.     public static void sendAToB(Serializable object) throws Exception{  
  31.         Connection conn=MqManager.newConnection();  
  32.         Channel channel=conn.createChannel();  
  33.         //声明headers转发器  
  34.         channel.exchangeDeclare("header_exchange", BuiltinExchangeType.HEADERS);  
  35.         //定义headers存储的键值对  
  36.         Map<String, Object> headers=new HashMap<String, Object>();  
  37.         headers.put("key""123456");  
  38.         headers.put("token""654321");  
  39.         //把键值对放在properties  
  40.         Builder properties=new BasicProperties.Builder();  
  41.         properties.headers(headers);  
  42.         properties.deliveryMode(2);//持久化  
  43.         //指定消息过期时间为12秒,队列上也可以指定消息的过期时间,两者以较小时间为准  
  44. //      properties.expiration("12000");//延时12秒,不会及时删除(在consuemr消费时判定是否过期,因为每条消息的过期时间不一致,删除过期消息就需要扫描整个队列)  
  45.         channel.basicPublish("header_exchange""" ,properties.build(), SerializationUtils.serialize(object));  
  46.         System.out.println("Send '"+object+"'");  
  47.         channel.close();  
  48.         conn.close();  
  49.     }  
  50.       
  51.     public static void main(String[] args) throws Exception {  
  52.         sendAToB("Hello World !");  
  53.     }  
  54. }  

  • 接收消息类

Java代码   收藏代码
  1. package com.demo.mq.rabbitmq.example08;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.HashMap;  
  5. import java.util.Map;  
  6.   
  7. import org.apache.commons.lang3.SerializationUtils;  
  8.   
  9. import com.demo.mq.rabbitmq.MqManager;  
  10. import com.rabbitmq.client.AMQP;  
  11. import com.rabbitmq.client.BuiltinExchangeType;  
  12. import com.rabbitmq.client.Channel;  
  13. import com.rabbitmq.client.Connection;  
  14. import com.rabbitmq.client.Consumer;  
  15. import com.rabbitmq.client.DefaultConsumer;  
  16. import com.rabbitmq.client.Envelope;  
  17.   
  18. /** 
  19.  * 接收消息类 
  20.  * @author sheungxin 
  21.  * 
  22.  */  
  23. public class Recv {  
  24.       
  25.     /** 
  26.      * 在topic转发器的基础上练习延时转发,设置队列过期时间(过期后自动删除),过期消息处理策略(转发给相匹配的queue) 
  27.      * 实验时启动接收类创建队列后,关闭该线程,使其进入未使用状态 
  28.      * @throws Exception 
  29.      */  
  30.     public static void recvAToB() throws Exception{  
  31.         Connection conn=MqManager.newConnection();  
  32.         Channel channel=conn.createChannel();  
  33.         channel.exchangeDeclare("header_exchange", BuiltinExchangeType.HEADERS);  
  34.         //设置队列过期时间为30秒,消息过期转发给指定转发器、匹配的routingkey(可不指定)  
  35.         Map<String, Object> args=new HashMap<String, Object>();  
  36.         args.put("x-expires"30000);//队列过期时间  
  37.         args.put("x-message-ttl"12000);//队列上消息过期时间  
  38.         args.put("x-dead-letter-exchange""exchange-direct");//过期消息转向路由  
  39.         args.put("x-dead-letter-routing-key""routing-delay");//过期消息转向路由相匹配routingkey  
  40.         //创建一个临时队列  
  41.         String queueName=channel.queueDeclare("tmp01",false,false,false,args).getQueue();  
  42.         //指定headers的匹配类型(all、any)、键值对  
  43.         Map<String, Object> headers=new HashMap<String, Object>();  
  44.         headers.put("x-match""all");//all any(只要有一个键值对匹配即可)  
  45.         headers.put("key""123456");  
  46. //      headers.put("token", "6543211");  
  47.         //绑定临时队列和转发器header_exchange  
  48.         channel.queueBind(queueName, "header_exchange""", headers);  
  49.         System.out.println("Received ...");  
  50.         Consumer consumer=new DefaultConsumer(channel){  
  51.             @Override  
  52.             public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body) throws IOException{  
  53.                 String mes=SerializationUtils.deserialize(body);  
  54.                 System.out.println(envelope.getRoutingKey()+":Received :'"+mes+"' done");  
  55.                 channel.basicAck(envelope.getDeliveryTag(), false);  
  56.             }  
  57.         };  
  58.         //关闭自动应答机制,默认开启;这时候需要手动进行应该  
  59.         channel.basicConsume(queueName, false, consumer);  
  60.     }  
  61.       
  62.     public static void main(String[] args) throws Exception {  
  63.         recvAToB();  
  64.     }  
  65.   
  66. }  

  • 延时消息处理类

Java代码   收藏代码
  1. package com.demo.mq.rabbitmq.example08;  
  2.   
  3. import java.io.IOException;  
  4. import org.apache.commons.lang3.SerializationUtils;  
  5. import com.demo.mq.rabbitmq.MqManager;  
  6. import com.rabbitmq.client.AMQP;  
  7. import com.rabbitmq.client.BuiltinExchangeType;  
  8. import com.rabbitmq.client.Channel;  
  9. import com.rabbitmq.client.Connection;  
  10. import com.rabbitmq.client.Consumer;  
  11. import com.rabbitmq.client.DefaultConsumer;  
  12. import com.rabbitmq.client.Envelope;  
  13.   
  14. /** 
  15.  * 延时消息处理类 
  16.  * @author sheungxin 
  17.  * 
  18.  */  
  19. public class DelayRecv {  
  20.   
  21.     /** 
  22.      * 创建队列并声明consumer用于处理转发过来的延时消息 
  23.      * @throws Exception 
  24.      */  
  25.     public static void delayRecv() throws Exception{  
  26.         Connection conn=MqManager.newConnection();  
  27.         Channel channel=conn.createChannel();  
  28.         channel.exchangeDeclare("exchange-direct", BuiltinExchangeType.DIRECT);  
  29.         String queueName=channel.queueDeclare().getQueue();  
  30.         channel.queueBind(queueName, "exchange-direct""routing-delay");  
  31.         Consumer consumer=new DefaultConsumer(channel){  
  32.             @Override  
  33.             public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body) throws IOException{  
  34.                 String mes=SerializationUtils.deserialize(body);  
  35.                 System.out.println(envelope.getRoutingKey()+":delay Received :'"+mes+"' done");  
  36.             }  
  37.         };  
  38.         //关闭自动应答机制,默认开启;这时候需要手动进行应该  
  39.         channel.basicConsume(queueName, true, consumer);  
  40.     }  
  41.       
  42.     public static void main(String[] args) throws Exception {  
  43.         delayRecv();  
  44.     }  
  45.   
  46. }  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值