本文基於spring-boot-starter-amqp依賴實現
RabbitMQ實現定時消息有兩種方式
- 基於消息TTL與死信交換
- 基於插件 RabbitMQ Delayed Message Plugin
基於消息TTL與死信交換
死信交換: 可以爲隊列設置一個死信exchange和routingKey,當隊列上產生死信時,死信會被投遞到設置好的exchange及對應的routingKey,說白點就是可以爲每個隊列設置一個"垃圾桶",產生死信就扔到垃圾桶裏,只不過垃圾桶也是一個正常的隊列.
如何會產生死信(怎樣會被扔到垃圾桶)
- 當消息被拒絕,並且拒絕後沒有重新進入隊列
- 由於消息TTL(剩餘生存時間),過期的消息
- 超過隊列長度而被刪除的消息
思路:
-
爲消息設置過期時間
-
把消息投遞到一個沒有消費者的隊列,ttl-queue 使消息成爲死信
-
爲ttl-queue設置死信交換,dead-letter-queue
-
爲dead-letter-queue添加消費者,監聽消息
先聲明那個沒有消費者的隊列,ttl-queue,併爲它指定"垃圾桶"(死信交換)
@Configuration
public class TtlConfig {
@Bean("myTtlExchange")
public Exchange ttlExchange() {
return new DirectExchange("mine-ttl-exchange");
}
@Bean("myTtlQueue")
public Queue ttlQueue() {
//設置在這個隊列上的私信交換(垃圾桶)->
// mine-dead-letter-exchange交換機,
// 並且routingKey爲mine.dead.letter
Map<String, Object> args = new HashMap<>(4);
args.put("x-dead-letter-exchange", "mine-dead-letter-exchange");
args.put("x-dead-letter-routing-key", "mine.dead.letter");
return new Queue("mine-ttl-queue", true, false, false, args);
}
@Bean
@DependsOn({"myTtlExchange", "myTtlQueue"})
public Binding ttlBinding(Queue myTtlQueue, Exchange myTtlExchange) {
return BindingBuilder.bind(myTtlQueue).to(myTtlExchange).with("mine.ttl").noargs();
}
}
監聽上面設置好的"垃圾桶"
@Component
@RabbitListener(bindings = @QueueBinding(
value = @Queue("mine-dead-letter-queue"),
exchange = @Exchange("mine-dead-letter-exchange"),
key = "mine.dead.letter" ))
public class DeadLetterListener {
@RabbitHandler
public void onMessage(String msg) {
System.out.println(msg);
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:ss:mm")));
}
}
爲消息設置過期時間
/**
* 每條消息單獨設置過期時間
*/
public void send() {
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:ss:mm")));
rabbitTemplate.convertAndSend("mine-ttl-exchange", "mine.ttl", "this is a message ",message -> {
//設置10秒過期
message.getMessageProperties().setExpiration("10000");
return message;
});
}
每條消息都設置過期時間,很靈活,若是固定的過期時間,可以在隊列上設置, 爲隊列設置 x-message-ttl 那在這個隊列上的每條消息的過期時間都爲 x-message-ttl 的值,只需要稍微修改一下ttl-queue
......
@Bean("myTtlQueue")
public Queue ttlQueue() {
//設置在這個隊列上的私信的去處->
// mine-dead-letter-exchange交換機,
// 並且routingKey爲mine.dead.letter
Map<String, Object> args = new HashMap<>(4);
args.put("x-dead-letter-exchange", "mine-dead-letter-exchange");
args.put("x-dead-letter-routing-key", "mine.dead.letter");
//過期時間由隊列統一設置
//注意不是 x-expires,x-expires爲隊列存活時間,
// x-message-ttl爲隊列內的消息存活時間
//注意更改隊列/交換機設置需要刪除原有的
args.put("x-message-ttl", 20000);
return new Queue("mine-ttl-queue", true, false, false, args);
}
.....
/**這樣的話也不用爲每條消息設置過期時間了
* 消息過期時間由隊列統一決定
*/
public void send1() {
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:ss:mm")));
rabbitTemplate.convertAndSend("mine-ttl-exchange", "mine.ttl", "this is a message ");
}
基於插件
插件名稱 rabbitmq_delayed_message_exchange
插件下載 (注意版本哦)
https://github.com/rabbitmq/rabbitmq-delayed-message-exchange
解壓後把插件放在RabbitMQ的plugin目錄下,默認路徑
lunix : /usr/lib/rabbitmq/lib/rabbitmq_server-version/plugins/
windows : C:\Program Files\RabbitMQ\rabbitmq_server-version\plugins\
啓用插件
# 查看插件是否在列表裏
rabbitmq-plugins list
# 啓用插件
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
# 啓用後再執行
rabbitmq-plugins list
如下,插件前有 [E*] 表示啓用了
......
[E*] rabbitmq_delayed_message_exchange 20171201-3.7.x
[ ] rabbitmq_event_exchange 3.7.15
[ ] rabbitmq_federation 3.7.15
[ ] rabbitmq_federation_management 3.7.15
[ ] rabbitmq_jms_topic_exchange 3.7.15
......
使用
-
申明一個延時消息的exchange 即:
- 交換機類型爲 x-delayed-message
- 爲交換機設置參數 "x-delayed-type" ,值爲四個交換機類型(direct ,fanout ,topic ,headers )
- 其餘使用與普通交換機無差別
@Component
@RabbitListener(bindings = @QueueBinding(
key = "mine.delay",
value = @Queue("mine-delay-queue"),
exchange = @Exchange( value = "mine-delay-exchange",
type = "x-delayed-message",
arguments = @Argument(name = "x-delayed-type",
value = ExchangeTypes.DIRECT))))
public class DelayListener {
@RabbitHandler
public void onMessage(String msg) {
System.out.println(msg);
System.out.println(LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
}
- 生產者發送消息時,設置延時的時間 x-delay
@Autowired
private RabbitTemplate rabbitTemplate;
public void send() {
System.out.println(LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
rabbitTemplate.convertAndSend("mine-delay-exchange", "mine.delay", "this is a message ",
message -> {
MessageProperties messageProperties = message.getMessageProperties();
//單位,毫秒
messageProperties.setDelay(10000);
return message;
});
}
轉載請註明出處
系列文章
- SpringBoot整合rabbitMQ,spring-boot-starter-amqp 的使用
- SpringBoot整合RabbitMQ,常用操作
- SpringBoot整合RabbitMQ,定時消息
- RabbitMQ 消息可靠投遞-消息落庫
作者:zolvces
鏈接:https://www.jianshu.com/p/31ed96971818
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。