配置:
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
publisher-confirms: true
config:
package com.uban.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
@Slf4j
public class DelayRabbitConfig {
/**
* 延迟队列 TTL 名称
*/
private static final String ORDER_DELAY_QUEUE = "user.order.delay.queue";
/**
* DLX,dead letter发送到的 exchange
* 延时消息就是发送到该交换机的
*/
public static final String ORDER_DELAY_EXCHANGE = "user.order.delay.exchange";
/**
* routing key 名称
* 具体消息发送在该 routingKey 的
*/
public static final String ORDER_DELAY_ROUTING_KEY = "order_delay";
public static final String ORDER_QUEUE_NAME = "user.order.queue";
public static final String ORDER_EXCHANGE_NAME = "user.order.exchange";
public static final String ORDER_ROUTING_KEY = "order";
/**
* 延迟队列配置
* <p>
* 1、params.put("x-message-ttl", 5 * 1000);
* 第一种方式是直接设置 Queue 延迟时间 但如果直接给队列设置过期时间,这种做法不是很灵活,(当然二者是兼容的,默认是时间小的优先)
* 2、rabbitTemplate.convertAndSend(book, message -> {
* message.getMessageProperties().setExpiration(2 * 1000 + "");
* return message;
* });
* 第二种就是每次发送消息动态设置延迟时间,这样我们可以灵活控制
**/
@Bean
public Queue delayOrderQueue() {
Map<String, Object> params = new HashMap<>();
// x-dead-letter-exchange 声明了队列里的死信转发到的DLX名称,
params.put("x-dead-letter-exchange", ORDER_EXCHANGE_NAME);
// x-dead-letter-routing-key 声明了这些死信在转发时携带的 routing-key 名称。
params.put("x-dead-letter-routing-key", ORDER_ROUTING_KEY);
return new Queue(ORDER_DELAY_QUEUE, true, false, false, params);
}
/**
* 需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。
* 这是一个完整的匹配。如果一个队列绑定到该交换机上要求路由键 “dog”,则只有被标记为“dog”的消息才被转发,
* 不会转发dog.puppy,也不会转发dog.guard,只会转发dog。
* @return DirectExchange
*/
@Bean
public DirectExchange orderDelayExchange() {
return new DirectExchange(ORDER_DELAY_EXCHANGE);
}
@Bean
public Binding dlxBinding() {
return BindingBuilder.bind(delayOrderQueue()).to(orderDelayExchange()).with(ORDER_DELAY_ROUTING_KEY);
}
@Bean
public Queue orderQueue() {
return new Queue(ORDER_QUEUE_NAME, true);
}
/**
* 将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。
* 符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词。因此“audit.#”能够匹配到“audit.irs.corporate”,但是“audit.*” 只会匹配到“audit.irs”。
**/
@Bean
public TopicExchange orderTopicExchange() {
return new TopicExchange(ORDER_EXCHANGE_NAME);
}
@Bean
public Binding orderBinding() {
// TODO 如果要让延迟队列之间有关联,这里的 routingKey 和 绑定的交换机很关键
return BindingBuilder.bind(orderQueue()).to(orderTopicExchange()).with(ORDER_ROUTING_KEY);
}
}
controller:
@PostMapping("/feign/createOrder")
public void createOrder(@RequestBody OrderTradeRecordRequest req) {
testService.createOrder(req);
devService.send(req);
System.out.println("===============sender已发送====================="+req);
}
sender:
@Component
public class DevService {
@Autowired
private AmqpTemplate amqpTemplate;
//有两种方法
public void send(OrderTradeRecordRequest req){
System.out.println("【订单生成时间】" + new Date().toString() +"【1分钟后检查订单是否已经支付】" + req.toString() );
//第一种,使用了jdk8的新特性
/*this.amqpTemplate.convertAndSend(DelayRabbitConfig.ORDER_DELAY_EXCHANGE, DelayRabbitConfig.ORDER_DELAY_ROUTING_KEY, req, message -> {
// 如果配置了 params.put("x-message-ttl", 5 * 1000); 那么这一句也可以省略,具体根据业务需要是声明 Queue 的时候就指定好延迟时间还是在发送自己控制时间
message.getMessageProperties().setExpiration(1 * 1000 * 60 + "");
return message;
});*/
//this.amqpTemplate.convertAndSend(DelayRabbitConfig.ORDER_QUEUE_NAME, req);
//第二种
MessagePostProcessor msg = new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message msg) throws AmqpException {
// 设置延迟毫秒值
msg.getMessageProperties().setExpiration("5000");
return msg;
}
};
this.amqpTemplate.convertAndSend(DelayRabbitConfig.ORDER_DELAY_EXCHANGE, DelayRabbitConfig.ORDER_DELAY_ROUTING_KEY, req, msg);
}
}
customer:
@Component
public class RabbitMQListener {
@Autowired
private TestService testService;
//直接消费模式
@RabbitListener(queues = {DelayRabbitConfig.ORDER_QUEUE_NAME})
public void consumeMessage(OrderTradeRecordRequest req){
System.out.println("===============接收==================="+req);
//TODO:表示时间已经到了,却还没付款,则需要处理为失效
Integer status = req.getStatus();
if (status.equals(1)||status==1){
Integer orderId=req.getOrderId();
testService.updateOrder(orderId);
}
}
}