1. Principe de mise en œuvre
Brève description de la file d'attente ttl + échange de lettres mortes
: utilisez deux files d'attente. Une file d'attente reçoit les messages sans consommation. Après avoir attendu un temps spécifié, le message meurt, puis l'échange de lettres mortes lié à la file d'attente l'achemine à nouveau vers une autre file d'attente pour fournir consommation des entreprises.
ttl : durée de survie du message x-message-ttl
2. Réalisation
- Déclarer les commutateurs et les files d'attente
@SpringBootConfiguration
public class RabbitDelayConfig {
/**
* 死信队列
*/
public static final String DEAD_QUEUE = "dead.queue";
/**
* 延时队列
*/
public static final String DELAY_QUEUE = "delay.queue";
/**
* 死信交换机
*/
public static final String DEAD_EXCHANGE = "dead.exchange";
/**
* 原交换机
*/
public static final String DELAY_EXCHANGE = "delay.exchange";
/**
* 声明延时队列(生产者投递消息)
*
*
* @return
*/
@Bean
public Queue getDelayQueue() {
//参数一:队列名称;参数二:队列中消息存活时间(单位ms);参数三:消息过期转发的死信交换机;参数四:死信队列和死信交换机绑定的rootingKey
Queue queue = QueueBuilder.durable(DELAY_QUEUE).ttl(10 * 1000).deadLetterExchange(DEAD_EXCHANGE).deadLetterRoutingKey("deadKey").build();
return queue;
}
/**
* 声明死信队列(接收过期转发消息)
*
* @return
*/
@Bean
public Queue getDeadQueue() {
return new Queue(DEAD_QUEUE, true);
}
/**
* 死信交换机(转发消息到死信队列)
*
* @return
*/
@Bean
public DirectExchange deadExchange() {
DirectExchange exchange = new DirectExchange(DEAD_EXCHANGE, true, false);
return exchange;
}
/**
* 原交换机(投递消息到延时队列)
*
* @return
*/
@Bean
public DirectExchange delayExchange() {
DirectExchange exchange = new DirectExchange(DELAY_EXCHANGE, true, false);
return exchange;
}
/**
* 绑定死信队列和死信交换机
*
* @return
*/
@Bean
public Binding bindDeadExchangeQueue() {
Binding binding = BindingBuilder.bind(getDeadQueue()).to(deadExchange()).with("deadKey");
return binding;
}
/**
* 绑定延时队列和原交换机
*
* @return
*/
@Bean
public Binding bindDelayExchangeQueue() {
Binding binding = BindingBuilder.bind(getDelayQueue()).to(delayExchange()).with("delay-routingKey");
return binding;
}
}
- Créer un producteur
@SpringBootTest
@RunWith(SpringRunner.class)
public class DelayMqTest {
@Resource
private RabbitTemplate rabbitTemplate;
@Test
public void send() {
rabbitTemplate.convertAndSend(RabbitDelayConfig.DELAY_EXCHANGE, "delay-routingKey", "延时消息");
System.out.println("发送消息时间:" + System.currentTimeMillis());
}
- Créer un consommateur (la file d'attente d'écoute est une file d'attente de lettres mortes)
@Component
public class DelayConsumer {
@RabbitListener(queues = RabbitDelayConfig.DEAD_QUEUE)
public void listenDead1(String message) {
System.out.println("接收时间:" + System.currentTimeMillis());
System.out.println("消费者一接收消息:" + message);
}
}
Résultat :
on peut voir que l'heure de réception du message et l'heure d'envoi du message sont fondamentalement cohérentes avec le temps de survie du message que nous avons défini ;
3. En plus
Il existe deux manières de définir le temps de survie des messages :
1. Définissez-le lors de la création d'une file d'attente différée. Après l'avoir défini ici, tous les messages de la file d'attente auront le même temps de survie :
@Bean
public Queue getDelayQueue() {
Queue queue = QueueBuilder.durable(DELAY_QUEUE).ttl(10 * 1000).deadLetterExchange(DEAD_EXCHANGE).deadLetterRoutingKey("deadKey").build();
return queue;
}
2. Définir lors de l'envoi d'un message. Après avoir défini ici, les messages dans la file d'attente ont des temps de survie différents :
@Test
public void send1() {
rabbitTemplate.convertAndSend(RabbitDelayConfig.DELAY_EXCHANGE, "delay-routingKey", "延时消息1111", message -> {
message.getMessageProperties().setExpiration(20 * 1000 + "");
return message;
});
System.out.println("发送消息时间:" + System.currentTimeMillis());
}
En particulier, si le temps de survie du message est défini pour les deux, le temps de survie réel du message est spécifié lors de l'envoi du message ; dans le code ci-dessus, le temps de survie réel du message est de 20 000 ms ;