Springboot集成RabbitMQ的延时队列

不想你离开。 提交于 2019-12-21 02:57:04

一、延时队列

延时队列的使用场景: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.
收到延时消息了:我是一个延时消息
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!