在项目实战中我们可能会遇到:
一般我们会想到的解决方法是利用定时任务定时查询数据库再进行相关操作,当数据量大的时候,定时任务的反复执行就会非常消耗内存,那么这个时候我们可以使用MQ消息队列中的延时消息处理来实现类似这种的业务操作。
RabbitMQ在设计之初本身不支持延时队列功能,但是我们可以通过TTL(Time To Live)来控制消息的生存时间结合DLX(Dead Letter Exchanges)死信队列达到消息的延迟处理。
1.rabbitMQ官网下载rabbitmq-delayed-message-exchange插件(为了不必要的麻烦一定要下载跟个人安装的rabbit版本一致)
放到服务器rabbitMQ安装包下的plugins目录中,并执行以下命令来安装插件:
rabbitmq-plugins enable rabbitmq-delayed-message-exchange
2.pom引用spring-boot-starter-amqp
org.springframework.boot
spring-boot-starter-amqp
3.添加yml配置
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
创建MqReceiver接收消息类,使用@RabbitListener注解监听消息并同时绑定queue队列、exchange交换机、routing key
@Component
public class MqReceiver {
/**
* rabbitmq_delayed_message_exchange插件版延时队列
* @param msg
* @param message
* @param channel
*/
@RabbitListener(bindings= @QueueBinding(value = @Queue(value = MQConstants.DELAY_QUEUE, durable = "true"),
exchange = @Exchange(value = MQConstants.DELAY_EXCHANGE,type=ExchangeTypes.DIRECT,
arguments=@Argument(name="x-delayed-type",value="direct"),delayed=Exchange.TRUE),
key = MQConstants.DELAY_KEY))
public void receiveDelay(String msg,Message message,Channel channel) {
System.out.println(message.toString());
System.out.println(message.getMessageProperties().getReceivedDelay());
System.out.println("-----------收到消息:"+msg+",当前时间:"+new Date());
}
}
注意:delayed = true 就是说明使用rabbitmq-delayed-message-exchange,原码解释:
众所周知@注解的使用极为方便,并且极大的减少的了代码量,那么对于初次使用者可能不是很明白整个QueueBinding 的流程,可以结合下面代码理解(仅作参考理解):
/**
* 延时队列交换机
*
* @return
*/
@Bean
public CustomExchange delayExchange() {
Map args = new HashMap<>();
args.put("x-delayed-type", "direct");
return new CustomExchange(DELAY_EXCHANGE, "x-delayed-message", true, false,args);
}
/**
* 定义延时队列
*
*/
@Bean
public Queue delayQueue() {
return new Queue(DELAY_QUEUE, true);
}
/**
* 给延时队列绑定交换机
*
* @return
*/
@Bean
public Binding binding() {
return BindingBuilder.bind(delayQueue()).to(delayExchange()).with(DELAY_KEY).noargs();
}
MQConstants类:
/**
* 延迟队列
*/
public final static String DELAY_QUEUE = "delay.queue";
/**
* 交换机名称
*/
public final static String DELAY_EXCHANGE = "delay.exchange";
/**
* routingKey
*/
public final static String DELAY_KEY = "delay.key";
发送消息:
@RestController
public class TestContoller {
@Autowired
private AmqpTemplate amqpTemplate;
@GetMapping(value = "/send/{exp}")
public String test(@PathVariable("exp") Integer exp) {
String msg = "发送时间:"+new Date();
amqpTemplate.convertAndSend(MQConstants.DELAY_EXCHANGE,MQConstants.THEATRE_DELAY_KEY,msg,message -> {
message.getMessageProperties().setDelay(exp);// 单位 毫秒
return message;
});
return "---------sendTime:"+new Date();
}
}
然后启动项目,可以看到rabbitMQ控制台显示出了定义的exchange,注意type显示为x-delayed-message
Queues,注意插件版的死信队列Features字段不会显示DLX
调用接口,定义10秒的延迟
控制台打印:
----我是francis, 谨以此记录自己精彩的程序人生。