SpringBoot RabbitMq 使用
最近业务场景需要,进行订单支付后,等待指定时间后检查订单是否支付完成,支付失败的话取消订单;支付成功不做其他操作;
通过面向百度开发,决定使用RabbitMq 作为消息中间件实现需要的功能;
通过资料翻阅知道,RabbitMq并没有延迟消息发送这个功能的;但可以通过其的两个特性TTL 和DLX 实现;
TTL :RabbitMq 运行我们为消息获取队列设置有效期; 当消息和队列同时设置时,以小值为准;
DLX:设置在队列上,作用是在于当队列中的消息被拒绝,过期获取队列达到最大长度被排出时,将消息发送到指定的交换器中,通过设置指定好的路由键,到底要接收消息的队列;
(这里个人理解是这样的,若有不当或错误的地方,望指出赐教;)
代码实现
- 引入依赖,配置RabbitMq
- 创建交换器和队列,并配置队列属性实现DLX
- 队列绑定交换器
- 测试发送TTL消息到设置DLX属性的队列
- 监听接收到转发消息的队列,实现接收延迟消息
第一步,引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置RabitMq
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: test
password: test
virtual-host: my_test
创建一个配置类,配置创建交换器和队列
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
/**
* 2019/8/21 14:21
*
* @Author lzm
*/
@Configuration
public class DmRabbitMqConfig {
/**
* 交换器
*/
public final static String DM_EXC = "DM_EXC";
/**
* 接收DLX转发消息的队列名字,同时作为路由键
*/
public final static String DM_QUEUE = "DM_QUEUE";
/**
* 配置DLX属性的队列名字,同时作为路由键
*/
public final static String DM_DLX_QUEUE = "DM_DLX_QUEUE";
/**
* 创建一个直接模式的交换器
* @return
*/
@Bean
public DirectExchange directExchange(){
return new DirectExchange(DM_EXC,true,false);
}
/**
* 创建一个普通的队列
* @return
*/
@Bean
public Queue dmQueue(){
Queue queue = new Queue(DM_QUEUE,true,false,false);
return queue;
}
/**
* 创建一个队列,并配置DLX 属性,
* 配置信息可查阅官网:https://www.rabbitmq.com/dlx.html
* @return
*/
@Bean
public Queue dlxQueue(){
Map<String,Object> map = new HashMap<>();
map.put("x-dead-letter-exchange",DM_EXC);
map.put("x-dead-letter-routing-key",DM_QUEUE);
Queue queue = new Queue(DM_DLX_QUEUE,true,false,false,map);
return queue;
}
// 两个队列和交换器进行绑定
@Bean
public Binding bindingDmQueue(){
return BindingBuilder.bind(dmQueue()).to(directExchange()).with(DM_QUEUE);
}
@Bean
public Binding bindinDlxQueue(){
return BindingBuilder.bind(dlxQueue()).to(directExchange()).with(DM_DLX_QUEUE);
}
}
写个测试类,发送消息进行测试;(进行消息发送时,交换器和队列必须是存在的了,否则会保错;)
@RunWith(SpringRunner.class)
@SpringBootTest
public class DmApplicationTests {
@Autowired
private RabbitTemplate template;
@Test
public void contextLoads() {
template.convertAndSend(DmRabbitMqConfig.DM_EXC,DmRabbitMqConfig.DM_DLX_QUEUE, "我是5秒前发生的消息,5秒前是"+LocalDateTime.now(), message -> {
message.getMessageProperties().setExpiration("5000");
return message;
});
}
写个消息接收类
@Component
public class Test {
@RabbitListener(queues = DmRabbitMqConfig.DM_QUEUE)
@RabbitHandler
public void get(String msg){
System.out.println("接收到消息,现在时间是:"+ LocalDateTime.now());
System.out.println(msg);
}
测试结果
接收到消息,现在时间是:2019-08-21T14:57:22.513
我是5秒前发生的消息,5秒前是2019-08-21T14:57:17.470