
点击上方蓝字关注我!
背景
这里我们有一个需求:
“
当用户支付成功时,需要修改订单状态;短信通知用户;通知仓库发货
”
原始解决方法
你首先想到的肯定是这样
public void paySuccess(String orderId) {
if (StringUtils.isNotBlank(orderId)) {
//1.修改订单状态
//2.发送短信通知用户
//3.通知仓库发货
}
}
在支付成功的方法里面调用修改订单的方法,调用短信通知用户的方法,调用仓库发货的方法。完事了,你觉得很简单嘛。
但是,产品经理说,我要改需求了,不止要短信通知,我还要微信通知。这个还是简单。
if (StringUtils.isNotBlank(orderId)) {
//1.修改订单状态
//2.发送短信通知用户
//3.通知仓库发货
//4.微信通知
}
过了一天产品经理又来加需求了,我还要可以QQ通知,这也不难。
if (StringUtils.isNotBlank(orderId)) {
//1.修改订单状态
//2.发送短信通知用户
//3.通知仓库发货
//4.微信通知
//5.QQ通知
}
过了一个月,产品经理又来了:“给我加个功能,我要支付成功后还可以发放优惠券,还要发放积分…”
需求没完没了,但这时你已经忘了支付成功的代码写在哪里了。
终于,你找到了,开始编写。突然,你意识到,不对呀,这个方法越来越臃肿了。而且每次还要来修改这个支付成功的方法,万一修改错误怎么办。
你还意识到一个问题,这些功能都是同步的,万一我调用微信通知的功能失败,难道就不能QQ通知,不能发放优惠券了么?还要全部都回滚。太不合常理了。
你苦思冥想,了解到了一个事件监听机制的方法,可以异步解耦,不正适合这个场景么。说干就干,代码重构走起。
事件监听解决方法
这里我就不说什么是事件监听机制了,概念百度一大把,我将从实际的例子说起,让你彻底理解这个机制是做什么的,什么时候用它。
我们先来定义一个支付事件类
/**
* Description: 支付事件
*
* @author Lvshen
* @version 1.0
* @date: 2020-8-28 13:56
* @since JDK 1.8
*/
public class PayEvent extends ApplicationEvent {
//订单id
private String orderId;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public PayEvent(Object source,String orderId) {
super(source);
this.orderId = orderId;
}
}
支付服务类这么写
/**
* Description:支付服务
*
* @author Lvshen
* @version 1.0
* @date: 2020-8-28 14:02
* @since JDK 1.8
*/
@Component
public class PayService {
@Autowired
public ApplicationEventPublisher applicationEventPublisher;
/**
* 支付成功后,发布事件
* @param orderId
*/
public void paySuccess(String orderId) {
if (StringUtils.isNotBlank(orderId)) {
applicationEventPublisher.publishEvent(new PayEvent(this, orderId));
}
}
}
这里支付成功后,会发布事件。这里的需求是支付后需要短信通知用户,通知订单修改状态,通知仓库准备发货。我们分别创建相关类来接收发布的事件。
OrderService
/**
* Description:订单服务
*
* @author Lvshen
* @version 1.0
* @date: 2020-8-28 14:10
* @since JDK 1.8
*/
@Component
public class OrderService {
@EventListener
public void updateOrderStatus(PayEvent payEvent) {
String orderId = payEvent.getOrderId();
//修改订单状态
System.out.println(String.format("支付成功,修改订单【%s】状态为已支付!!!",orderId));
}
}
当订单服务监听到支付服务发过来的数据,开始修改数据。
SmsService
/**
* Description:短信服务
*
* @author Lvshen
* @version 1.0
* @date: 2020-8-28 14:16
* @since JDK 1.8
*/
@Component
public class SmsService {
@EventListener
public void sendMessage(PayEvent payEvent) {
String orderId = payEvent.getOrderId();
//短信功能
System.out.println(String.format("支付成功,发送【%s】短信",orderId));
}
}
短信服务监听支付事件,当支付成功,监听到事件,并将支付成功的消息发送给用户。
WarehouseService
/**
* Description:仓库服务
*
* @author Lvshen
* @version 1.0
* @date: 2020-8-28 14:21
* @since JDK 1.8
*/
@Component
public class WarehouseService {
@EventListener
public void sendProduct(PayEvent payEvent) {
String orderId = payEvent.getOrderId();
//发货功能
System.out.println(String.format("支付成功,准备发货,订单【%s】",orderId));
}
}
同样,当仓库监听到支付成功的事件,开始准备发货。
测试事件发布机制【即当支付成功时】
显示结果
当需要添加微信通知时,只需要写一个微信服务类,在监听支付成功的事件了。同理,QQ通知和优惠券下发,积分下发等功能采用同样的方法。
这样我们不用去改动支付成功这个方法了,毕竟修改核心方法还是很危险的。
这里我抛出2个问题:
“
1.如果事件发布后,事务还没提交,另一边监听到了,可能会造成数据不准确问题,还有空指针异常问题。
2.如果发布事件一方有操作数据库,监听事件一方也有操作数据库。当监听事件一方操作数据库时抛出异常,发布事件一方需要回滚么。
”
不知这两个问题你的解决方案是什么呢?
往期推荐


扫码二维码
获取更多精彩
Lvshen_9


原文始发于微信公众号(Lvshen的技术小屋):开发实战-我用Spring的事件监听机制实现了模块的解耦
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/262589.html