「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」
一、前言
先来数据互联网酒店的业务。 再从订单入手,分析个订单场景。
互联网酒店下单业务流程:
- 客户查询酒店房间
- 预定房间
- 付款
- 更新优惠券状态
- 推送微信消息
下单功能:预定、付款、生成订单信息、更新优惠券信息、推送微信通知、后台查看订单详情。
下单流程可分为:
- 同步方式下单:上面就是
- 异步方式下单:如下
异步方式下单,如图:
通过加入消息队列(
RocketMQ)来进行异步话。系统只需要发送一个订单创建的消息到
RocketMQ中,推送微信通知的功能就交给消费服务去执行了。不用同步等待推送微信消息成功后才返回结果,来提高系统的吞吐量。
二、代码实战
代码部分分为:
- 优惠券服务(
CouponService) - 订单服务(
OrderService)
订单服务(OrderService):创建订单
- 保存订单数据
- 保存订单商品数据
- 更新优惠券状态
配置类如下:
@Configuration
public class OrderProducerConfiguration {
@Value("${rocketmq.namesrv.address}")
private String namesrvAddress;
@Value("${rocketmq.order.producer.group}")
private String orderProducerGroup;
@Value("${rocketmq.order.finished.producer.group}")
private String orderPayProducerGroup;
/**
* 订单消息生产者
*
* @return 订单消息rocketmq的生产者对象
*/
@Bean(value = "orderMqProducer")
public DefaultMQProducer orderMqProducer() throws MQClientException {
DefaultMQProducer producer = new DefaultMQProducer(orderProducerGroup);
producer.setNamesrvAddr(namesrvAddress);
producer.start();
return producer;
}
}
订单服务如下:
@Service
public class OrderServiceImpl implements OrderService {
private static final Logger LOGGER = LoggerFactory.getLogger(OrderServiceImpl.class);
/**
* TODO 正常获取酒店房间数据 应该调用酒店服务的rpc接口 由于没分模块则本地调用
*/
@Autowired
private HotelRoomService hotelRoomService;
/**
* 订单事件通知管理组件
*/
@Autowired
private OrderEventInformManager orderEventInformManager;
/**
* mysql dubbo服务
*/
@Reference(version = "1.0.0",
interfaceClass = MysqlApi.class,
cluster = "failfast")
private MysqlApi mysqlApi;
/**
* redis dubbo服务
*/
@Reference(version = "1.0.0",
interfaceClass = RedisApi.class,
cluster = "failfast")
private RedisApi redisApi;
/**
* TODO 本质上是走rpc远程调用 这里由于没拆分模块即本地调用
*/
@Autowired
private CouponService couponService;
/**
* 完成定时事务消息topic
*/
@Value("${rocketmq.order.finished.topic}")
private String orderFinishedTopic;
/**
* 完成订单 下发权益消息事务消息
*/
@Autowired
@Qualifier(value = "orderFinishedTransactionMqProducer")
private TransactionMQProducer orderFinishedTransactionMqProducer;
@Override
public CommonResponse<CreateOrderResponseDTO> createOrder(OrderInfoDTO orderInfoDTO) {
// TODO 1.校验库存 由于我们后台系统配置为不减库存 这里库存不做校验
// TODO 可以通过状态模式来校验订单的流转和保存订单操作日志
// 保存订单数据
this.saveOrderInfo(orderInfoDTO);
// 保存订单商品数据
this.saveOrderItemInfo(orderInfoDTO);
// 调用优惠券服务更新优惠券状态:修改优惠券状态
couponService.usedCoupon(orderInfoDTO.getId(), orderInfoDTO.getCouponId(), orderInfoDTO.getPhoneNumber());
// 发送订单消息到mq中
orderEventInformManager.informCreateOrderEvent(orderInfoDTO);
CreateOrderResponseDTO createOrderResponseDTO = new CreateOrderResponseDTO();
createOrderResponseDTO.setOrderNo(orderInfoDTO.getOrderNo());
createOrderResponseDTO.setOrderId(orderInfoDTO.getId());
return CommonResponse.success(createOrderResponseDTO);
}
}
通知订单消息:
@Service
public class OrderEventInformManagerImpl implements OrderEventInformManager {
private static final Logger LOGGER =
LoggerFactory.getLogger(OrderEventInformManagerImpl.class);
@Autowired
@Qualifier(value = "orderMqProducer")
private DefaultMQProducer orderMqProducer;
/**
* 订单消息topic
*/
@Value("${rocketmq.order.topic}")
private String orderTopic;
@Override
public void informCreateOrderEvent(OrderInfoDTO orderInfoDTO) {
// 订单状态顺序消息
this.sendOrderMessage(MessageTypeEnum.WX_CREATE_ORDER, orderInfoDTO);
}
/**
* 发送订单消息
*
* @param messageTypeEnum 订单消息类型
*/
private void sendOrderMessage(MessageTypeEnum messageTypeEnum,
OrderInfoDTO orderInfoDTO) {
OrderMessageDTO orderMessageDTO = new OrderMessageDTO();
orderMessageDTO.setMessageType(messageTypeEnum);
orderMessageDTO.setContent(JSON.toJSONString(orderInfoDTO));
Message message = new Message();
message.setTopic(orderTopic);
message.setBody(JSON.toJSONString(orderMessageDTO)
.getBytes(StandardCharsets.UTF_8));
try {
orderMqProducer.send(message, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg,
Object orderId) {
// 订单id
Integer id = (Integer) orderId;
int index = id % mqs.size();
return mqs.get(index);
}
}, orderInfoDTO.getId());
} catch (Exception e) {
// 发送订单消息失败
LOGGER.error("send order message fail,error message:{}", e.getMessage());
}
}
}