RabbitMQ 异步消息通知实现支付业务解耦
业务背景
目前,黑马商城的支付业务流程是同步调用的,包含以下三步:
- 余额扣减:向用户服务发起远程调用,完成余额扣减。
- 支付流水更新:在支付服务本地更新支付流水状态。
- 订单状态更新:向交易服务发起远程调用,更新订单状态。
这三步中,余额扣减和支付流水更新是支付的核心业务,采用同步调用没有问题;而订单状态更新则不属于核心业务,属于边缘业务,采用同步调用不合适。为了优化性能,应将边缘业务(如订单状态更新、短信通知、积分增加等)通过 RabbitMQ 实现异步处理。
业务改造思路
- 解耦支付核心业务与边缘业务:支付核心业务(余额扣减和支付流水更新)依然保持同步,而边缘业务通过 MQ 发送消息,消费者(如交易服务)监听相应的队列进行处理。
- 使用 Direct Exchange 类型:由于不同的服务只关心特定的支付状态(如支付成功或支付失败),采用
direct
类型交换机,根据业务需求发送相应的消息。
设计方案
- 交换机选择:使用
direct
交换机,定义特定的routing key
来区分不同的消息(如支付成功或支付失败)。 - 队列设计:
- 对于交易服务,创建两个队列:一个用于处理支付成功的业务,另一个用于支付失败的业务。
- 队列命名方式示例:
trade_pay_success_queue
、trade_pay_fail_queue
。 - 每个队列有对应的消费者,监听指定的队列并处理相关业务。
配置和代码实现
- 依赖引入:在支付服务和交易服务中引入
spring-boot-starter-amqp
依赖。
<!--AMQP依赖,包含RabbitMQ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
- MQ 地址配置:在
application.properties
或application.yml
文件中配置 RabbitMQ 的连接信息,包括host
、port
、username
、password
和virtual host
。建议将配置抽取到共享配置里,避免重复编写。
spring:
rabbitmq:
host: 192.168.100.212 # 主机名
port: 5672 # 端口
virtual-host: / # 虚拟主机
username: nhuan # 用户名
password: 123456 # 密码
- 消息转换器配置:使用 Jackson 转换器进行消息的序列化与反序列化,将配置类写到 common 里,每一个微服务都能使用。
@Configuration
public class MqConfig {
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
}
注意:我们这里是pay service,是在这个pay模块或者是trade模块。所以它们的包名都不一样,所以根本不可能被扫描到,因此的话,我们采用的是这个spring自动装配的一个原理啊,是在spring的factors文件里来。添加mq的config。以这种方式让spring boot能够扫描到它,从而让它生效好吧。
- 消息监听器配置:
- 在交易服务中实现消息消费者,监听支付成功或支付失败的消息。
- 使用
@RabbitListener
注解标注监听方法,并指定队列、交换机及绑定的routing key
。
消息发送和消费
- 支付服务发送消息:
- 通过
RabbitTemplate
将支付状态(支付成功或支付失败)发送到 RabbitMQ。 - 使用
convertAndSend
方法,指定交换机、路由键和消息内容。 - 采用
try-catch
结构处理消息发送异常,确保不会影响核心支付业务。
- 通过
- 交易服务消费消息:
- 消费者监听到支付成功的消息后,调用订单服务接口更新订单状态为“已支付”。
- 通过
@RabbitListener
注解,指定队列和绑定关系。 - 监听到消息后,获取订单 ID 并调用
OrderService
更新订单状态。
测试和验证
- 队列和交换机创建:启动服务后,通过 RabbitMQ 管理后台检查是否成功创建了交换机、队列和绑定关系。
- 支付业务验证:进行支付操作后,检查数据库中的余额扣减和订单状态更新是否成功。同时,通过 RabbitMQ 检查消息是否成功发送到队列,消费者是否成功消费消息并更新订单状态。
总结
通过将支付流程中的非核心业务(如订单状态更新、短信通知、积分增加)通过 RabbitMQ 实现异步通知,可以有效解耦业务,提高系统的性能和可靠性。这种设计遵循了异步解耦的思想,使得核心支付流程不会受到其他业务影响。