![c915a096f0331e31a72bee537d685ad6.png](https://i-blog.csdnimg.cn/blog_migrate/949482d290375d6042b1651f8dbcfee6.jpeg)
背景
这里我们有一个需求:
“
当用户支付成功时,需要修改订单状态;短信通知用户;通知仓库发货
”
原始解决方法
你首先想到的肯定是这样
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));
}
}
同样,当仓库监听到支付成功的事件,开始准备发货。
测试事件发布机制【即当支付成功时】
![99715efa62c89e8b021a95ed5ebb98b8.png](https://i-blog.csdnimg.cn/blog_migrate/b52f89d0467490bfdeb38d94263660ed.jpeg)
显示结果
![48b39d5b46ee064b1f6b838d78abe520.png](https://i-blog.csdnimg.cn/blog_migrate/1fd3982d0f31c7fb0950418aacc618eb.png)
当需要添加微信通知时,只需要写一个微信服务类,在监听支付成功的事件了。同理,QQ通知和优惠券下发,积分下发等功能采用同样的方法。
这样我们不用去改动支付成功这个方法了,毕竟修改核心方法还是很危险的。
这里我抛出2个问题:
“
1.如果事件发布后,事务还没提交,另一边监听到了,可能会造成数据不准确问题,还有空指针异常问题。
2.如果发布事件一方有操作数据库,监听事件一方也有操作数据库。当监听事件一方操作数据库时抛出异常,发布事件一方需要回滚么。
”
不知这两个问题你的解决方案是什么呢?
来源:公众号Lvshen_9