RabbitMQ服务端需要安装rabbitmq_delayed_message_exchange插件
CentOS7 为RabbitMQ安装延时队列插件
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
spring:
rabbitmq:
host: 127.0.0.1
username: 123456
password: 123456
port: 5672
# 开启消息手动应答
listener:
direct:
acknowledge-mode: MANUAL
simple:
acknowledge-mode: MANUAL
/**
* RabbitMQ 配置类
*
* 说明:
* 1. 定义超时支付订单队列
* 2. 定义广播模式的延时交换机
* 3. 绑定超时支付订单队列与延时交换机
* 4. 定义消息模板用于发布消息,并且设置其消息转换器
*
* @author MoCha
* @date 2020/4/14
*/
public class RabbitMqConfig {
/**
* 定义超时支付订单队列
*
* @return 超时支付订单队列
*/
@Bean
public Queue timeOutOrderQueue() {
// 表示持久化该队列,RabbitMQ服务重启后该队列仍旧保留
return QueueBuilder.durable(RabbitMqConstants.TIMEOUT_ORDER_QUEUE).build();
}
/**
* 定义广播模式的延时交换机 无需绑定路由
*/
@Bean
public Exchange delayExchange() {
Map<String, Object> arguments = new HashMap<>(4);
arguments.put("x-delayed-type", "direct");
// 如果不调用autoDelete()方法,那么autoDelete就是false
// 可以不调用durable(boolean isDurable),默认为true
// 调用delayed()后,delayed变量设置为true
return ExchangeBuilder.fanoutExchange(RabbitMqConstants.DELAY_EXCHANGE)
.withArguments(arguments).delayed().build();
}
/**
* 绑定超时支付订单队列与延时交换机
*/
@Bean
public Binding delayExchangeAndTimeOutOrderQueueBinding() {
return BindingBuilder.bind(timeOutOrderQueue()).to(delayExchange()).with(StringPool.EMPTY).noargs();
}
/**
* 定义消息转换器
*/
@Bean
Jackson2JsonMessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
/**
* 定义消息模板用于发布消息,并且设置其消息转换器
*/
@Bean
RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
// 定义消息转换器并设置
rabbitTemplate.setMessageConverter(jsonMessageConverter());
return rabbitTemplate;
}
@Bean
RabbitAdmin rabbitAdmin(final ConnectionFactory connectionFactory) {
return new RabbitAdmin(connectionFactory);
}
}
RabbitMQ常量类
/**
* RabbitMQ 常量类
*
* @author MoCha
* @date 2020/4/14
*/
public final class RabbitMqConstants {
/**
* 超时支付订单 延时交换机
*/
public static final String DELAY_EXCHANGE = "delay.exchange";
/**
* 超时支付订单 延时队列
*/
public static final String TIMEOUT_ORDER_QUEUE = "timeout_order_queue";
/**
* 阻止实例化
*
* Prevents instantiation
*/
private RabbitMqConstants() {
}
}
在需要使用RabbitMQ的主启动类上添加该注解
/**
* 开启 RabbitMQ
*
* @author MoCha
* @date 2020/4/15
*/
@Documented
@Target({
ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(RabbitMqConfig.class)
public @interface EnableRabbitMq {
}
/**
* 在主启动类上添加@EnableRabbitMq,引入我们编写的RabbitMQ配置类
*
* @author MoCha
* @date 2020/4/15
*/
@EnableRabbitMq
@SpringBootApplication(scanBasePackages = {
"top.yangzefeng.server.marketing", "top.yangzefeng.common"})
public class IceStreamServerMarketingApplication {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(IceStreamServerMarketingApplication.class);
springApplication.setBanner(new IceStreamBanner());
springApplication.run(args);
}
}
/**
* @author MoCha
* @date 2020/4/15
*/
@Slf4j
@RestController
@RequestMapping("/rabbitmq")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class TestController {
/**
* 超时支付延时时间
*
* 说明:
* 1. 根据message.getMessageProperties().setDelay(timeoutDelayTime);可知setDelay的参数类型为Integer
*/
@Value("${rabbitmq.timeOutDelayTime}")
private Integer timeoutDelayTime;
private final RabbitTemplate rabbitTemplate;
private final OrderService orderService;
@GetMapping("/test")
public String createOrderTest() {
// 创建订单
Order order = new Order();
order.setOrderId(IdWorker.getId());
order.setOrderTradeNumber(IdWorker.getTimeId());
order.setUserId(0);
order.setOrderAmount(BigDecimal.TEN);
order.setOrderStatus(OrderStatusEnum.NOT_PAID.getStatus());
order.setPaymentType(0);
order.setOrderType(0);
// 发送订单到消息队列
rabbitTemplate.convertAndSend(RabbitMqConstants.DELAY_EXCHANGE, StringPool.EMPTY, order, message -> {
message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
// 毫秒为单位,指定此消息的延时时长,设置10秒延时
message.getMessageProperties().setDelay(timeoutDelayTime);
return message;
});
orderService.save(order);
log.info("创建订单成功");
return "创建订单成功";
}
}
/**
* 订单消息监听器
*
* 说明:
* 1. @RabbitListener指定目标方法来作为消费消息的方法,通过注解参数指定所监听的队列或者Binding
*
* @author MoCha
* @date 2020/4/14
*/
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OrderListener {
/**
* 超时支付延时时间
*/
@Value("${rabbitmq.timeOutDelayTime}")
private Integer timeoutDelayTime;
private final OrderService orderService;
@RabbitListener(queues = RabbitMqConstants.TIMEOUT_ORDER_QUEUE)
public void process(Order order, Message message, Channel channel) throws IOException {
log.info("超时时间为 [{}] ms,超时订单信息,order = [{}]",
timeoutDelayTime, JsonUtils.prettyPrint(order));
try {
orderService.timeOutCloseOrder(order.getOrderId());
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
log.info("超时订单处理完毕");
} catch (Exception e) {
channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
}
}
}
由于Order实体类使用了LocalDateTime,并且服务自身内部对LocalDateTime序列化和反序列化作了处理,参考Spring Boot Java8 LocalDateTime日期序列化与反序列化 解决方案,所以在RabbitMQ配置类中,不需要再另外设置jsonMessageConverter
,以及将jsonMessageConverter
填充到RabbitTemplate
说明:不同版本的spring boot,对于使用BindingBuilder来创建Binding使用方式有点差异
/**
* 绑定超时支付订单队列与延时交换机
*
*/
@Bean
public Binding delayExchangeAndTimeOutOrderQueueBinding() {
// 2.1.9.RELEASE
// 通过分析2.2.6.RELEASE版本下,BindingBuilder源码的处理,可以改造成这样
return BindingBuilder.bind(timeOutOrderQueue()).to(delayExchange()).with(StringPool.EMPTY).noargs();
}
@Bean
public Binding delayExchangeAndTimeOutOrderQueueBinding() {
// 2.2.6.RELEASE
return BindingBuilder.bind(timeOutOrderQueue()).to(delayExchange());
}
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.9.RELEASEversion>
<relativePath/>
parent>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
<version>2.1.9.RELEASEversion>
dependency>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.6.RELEASEversion>
<relativePath/>
parent>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
<version>2.2.6.RELEASEversion>
dependency>