springboot 使用RabbitMQ实现延迟队列

RabbitMQ延迟消息实现方式

image

延迟任务通过消息的TTL和Dead Letter Exchange来实现。我们需要建立2个队列,一个用于发送消息,一个用于消息过期后的转发目标队列。

生产者输出消息到Queue1,并且这个消息是设置有有效时间的,比如60s。消息会在Queue1中等待60s,如果没有消费者收掉的话,它就是被转发到Queue2,Queue2有消费者,收到,处理延迟任务。

具体创建步骤如下:

1. 创建2个路由、2个队列:

路由:Exchange1、Exchange2。(均为普通路由)

队列:Queue1、Queue2。(Queue1为特殊队列,Queue2为普通队列)

Queue1需要设置 Dead letter exchange 参数(名称:x-dead-letter-exchange,值为刚才创建的Exchange2),当Queue1中的消息过期后,通过路由Exchange2转发。

2. 绑定

将Exchange1与Queue1绑定,Exchange2与Queue2绑定

Java实现

1.引入jar包

 
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>

2.创建路由、队列 (这部分在程序运行前手动执行,运行一次即可。也可以通过rabbit管理页面创建)


import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

import org.junit.Test;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

/**
 * 创建路由、队列,并绑定
 */
public class DlConfig {

    final static String firstExchange = "firstExchange";
    final static String firstQuque = "firstQuque";
    final static String twoExchange = "twoExchange";
    final static String twoQueue = "twoQueue";
    final static String routingKey = "ddd";
    
    /**
     * 手动执行,创建路由、队列
     */
    @Test
    public void binding() throws IOException, TimeoutException{
        
        //建立连接,创建通道
        ConnectionFactory fc = new ConnectionFactory();
        fc.setHost("localhost");
        fc.setPort(5672);
        fc.setUsername("guest");
        fc.setPassword("guest");
        
        Connection conn = fc.newConnection();
        Channel channel = conn.createChannel();
        
        channel.exchangeDelete(firstExchange);  //删除路由
        channel.exchangeDelete(twoExchange);
        channel.exchangeDeclare(firstExchange, BuiltinExchangeType.DIRECT);  //创建路由
        channel.exchangeDeclare(twoExchange, BuiltinExchangeType.DIRECT);
        
        channel.queueDelete(firstQuque);  //删除队列
        Map<String,Object> map = new HashMap<String,Object>();  //设置队列参数
        map.put("x-dead-letter-exchange", twoExchange);
        channel.queueDeclare(firstQuque, true, false, false, map);  //创建队列
        
        channel.queueDelete(twoQueue);
        channel.queueDeclare(twoQueue, true, false, false, null);        
        
        channel.queueBind(firstQuque, firstExchange, routingKey);  //绑定路由、队列
        channel.queueBind(twoQueue, twoExchange, routingKey);
         
        channel.close();
        conn.close();
    }

    
}

3,消息发送者


import java.time.LocalDateTime;

import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 消息生产者
 */
@Component
public class DlProducer {
    
    /** 引入rabbit的操作模板 */
    @Autowired
    RabbitTemplate rabbitTemplate;
    
    /**
     * 发送信息
     */
    public void sender(){
        
        MessagePostProcessor msg = new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message msg) throws AmqpException {
                // 设置延迟毫秒值
                msg.getMessageProperties().setExpiration("5000");
                return msg;
            }
        };
        rabbitTemplate.convertAndSend(DlConfig.firstExchange, DlConfig.routingKey, "哈哈哈哈哈"+LocalDateTime.now(), msg);
        
        
        // 另一种写法 使用拉姆达表达式
        rabbitTemplate.convertAndSend(DlConfig.firstExchange, DlConfig.routingKey, "哈哈哈哈哈"+LocalDateTime.now(), message -> {
            // 设置延迟毫秒值
            message.getMessageProperties().setExpiration(String.valueOf(5000));
            return message;
        });
        
    }

}

4.消息接收者


import java.time.LocalDateTime;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 消息消费者
 */
@Component
public class DlConsumer {
    
    /**
     * 接收消息,监听 twoQueue 队列
     */
    @RabbitListener(queues = "twoQueue")
    public void ls(String message){
        System.out.println(message+" | "+LocalDateTime.now());
    }
    

}

运行结果:

哈哈哈哈哈2018-07-26T18:24:06.981 | 2018-07-26T18:24:11.993
哈哈哈哈哈2018-07-26T18:24:06.988 | 2018-07-26T18:24:11.995

猜你喜欢

转载自blog.csdn.net/liyongbing1122/article/details/81225259