Springboot集成RabbitMQ的延时队列
一、延时队列
延时队列的使用场景:1.未按时支付的订单,30分钟过期之后取消订单;2.给活跃度比较低的用户间隔N天之后推送消息,提高活跃度;3.过1分钟给新注册会员的用户,发送注册邮件等。
实现延时队列的方式有两种:
通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能;
使用rabbitmq-delayed-message-exchange插件实现延迟功能;
注意: 延迟插件rabbitmq-delayed-message-exchange是在RabbitMQ 3.5.7及以上的版本才支持的,依赖Erlang/OPT 18.0及以上运行环境。
由于使用死信交换器相对曲折,本文重点介绍第二种方式,使用rabbitmq-delayed-message-exchange插件完成延迟队列的功能。
二.下载并且安装erlang和RabbitMQ
1.erlang下载地址 :http://www.erlang.org/downloads
2.RabbitMQ下载地址:http://www.rabbitmq.com/download.htm
3.安装教程:https://blog.51cto.com/10836356/2082963
三.代码实现
3.1.新增依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
3.2.修改application.yml
spring:
application:
name: springboot-rabbitmq-sender
rabbitmq:
host: 127.0.0.1
username: guest
password: guest
3.3.配置队列
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.amqp.core.Queue;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class config {
public static final String IMMEDIATE_QUEUE = "queue.demo.immediate";//立即消费的队列名称
public static final String IMMEDIATE_EXCHANGE = "exchange.demo.immediate";//立即消费的exchange
public static final String IMMEDIATE_ROUTING_KEY = "routingkey.demo.immediate";//立即消费的routing-key 名称
public static final String DELAY_QUEUE= "queue.demo.delay";//延时消费的队列名称
public static final String DEAD_LETTER_EXCHANGE = "exchange.demo.delay";//延时消费的exchange
public static final String DELAY_ROUTING_KEY = "routingkey.demo.delay";//延时消费的routing-key名称
// 创建一个立即消费队列
@Bean
public Queue immediateQueue() {
// 第一个参数是创建的queue的名字,第二个参数是是否支持持久化
return new Queue(IMMEDIATE_QUEUE, true);
}
// 创建一个延时队列
@Bean
public Queue delayQueue() {
Map<String, Object> params = new HashMap<>();
// x-dead-letter-exchange 声明了队列里的死信转发到的DLX名称,
params.put("x-dead-letter-exchange", IMMEDIATE_EXCHANGE);
// x-dead-letter-routing-key 声明了这些死信在转发时携带的 routing-key 名称。
params.put("x-dead-letter-routing-key", IMMEDIATE_ROUTING_KEY);
return new Queue(DELAY_QUEUE, true, false, false, params);
}
public DirectExchange immediateExchange() {
// 一共有三种构造方法,可以只传exchange的名字, 第二种,可以传exchange名字,是否支持持久化,是否可以自动删除,
//第三种在第二种参数上可以增加Map,Map中可以存放自定义exchange中的参数
return new DirectExchange(IMMEDIATE_EXCHANGE, true, false);
}
@Bean public DirectExchange deadLetterExchange() {
// 一共有三种构造方法,可以只传exchange的名字, 第二种,可以传exchange名字,是否支持持久化,是否可以自动删除,
// 第三种在第二种参数上可以增加Map,Map中可以存放自定义exchange中的参数
return new DirectExchange(DEAD_LETTER_EXCHANGE, true, false);
}
//把立即消费的队列和立即消费的exchange绑定在一起
@Bean
public Binding immediateBinding() {
return BindingBuilder.bind(immediateQueue()).to(immediateExchange()).with(IMMEDIATE_ROUTING_KEY);
}
//把延时消费的队列和延时消费的exchange绑定在一起
@Bean
public Binding delayBinding() {
return BindingBuilder.bind(delayQueue()).to(deadLetterExchange()).with(DELAY_ROUTING_KEY);
}
}`
3.4 发送消息
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 生产者生产消息
*/
@Component
public class ImmediateSender {
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(String msg, int delayTime) {
System.out.println("msg="+",delayTime" + delayTime);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
this.rabbitTemplate.convertAndSend(config.DEAD_LETTER_EXCHANGE, config.DELAY_ROUTING_KEY, msg, message -> {
message.getMessageProperties().setExpiration(delayTime + "");
System.out.println(sdf.format(new Date()) + " Delay sent."); return message;
});
}
}
3.5 消费消息
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 消费者消费消息
*/
@Component
@EnableRabbit
@Configuration
public class ImmediateReceiver {
@RabbitListener(queues = config.IMMEDIATE_QUEUE)
@RabbitHandler
public void get(String msg) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("收到延时消息时间:"+sdf.format(new Date()) + " Delay sent.");
System.out.println("收到延时消息了:" + msg);
}
}
3.6 测试队列
import com.example.robbitmq.Config1.ImmediateSender;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest
public class AmqpApplicationTests {
@Autowired
ImmediateSender immediateSender;
@Test
public void test() {
immediateSender.send("我是一个延时消息",3000);//3秒
//让服务一直挂起,不然,接收消息时,服务已经停了
while(true){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.7 测试结果
msg=,delayTime3000
2019-12-20 15:22:23 Delay sent.
收到延时消息时间:2019-12-20 15:22:26 Delay sent.
收到延时消息了:我是一个延时消息
来源:CSDN
作者:qq_44051354
链接:https://blog.csdn.net/qq_44051354/article/details/103634022