用Spring的事件监听机制实现模块的解耦

背景

这里我们有一个需求:

当用户支付成功时,需要修改订单状态;短信通知用户;通知仓库发货

原始解决方法

你首先想到的肯定是这样

1
2
3
4
5
6
7
public void paySuccess(String orderId) {
if (StringUtils.isNotBlank(orderId)) {
//1.修改订单状态
//2.发送短信通知用户
//3.通知仓库发货
}
}

在支付成功的方法里面调用修改订单的方法,调用短信通知用户的方法,调用仓库发货的方法。完事了,你觉得很简单嘛。

但是,产品经理说,我要改需求了,不止要短信通知,我还要微信通知。这个还是简单。

1
2
3
4
5
6
if (StringUtils.isNotBlank(orderId)) {
//1.修改订单状态
//2.发送短信通知用户
//3.通知仓库发货
//4.微信通知
}

过了一天产品经理又来加需求了,我还要可以QQ通知,这也不难。

1
2
3
4
5
6
7
if (StringUtils.isNotBlank(orderId)) {
//1.修改订单状态
//2.发送短信通知用户
//3.通知仓库发货
//4.微信通知
//5.QQ通知
}

过了一个月,产品经理又来了:“给我加个功能,我要支付成功后还可以发放优惠券,还要发放积分…”

需求没完没了,但这时你已经忘了支付成功的代码写在哪里了。

终于,你找到了,开始编写。突然,你意识到,不对呀,这个方法越来越臃肿了。而且每次还要来修改这个支付成功的方法,万一修改错误怎么办。

你还意识到一个问题,这些功能都是同步的,万一我调用微信通知的功能失败,难道就不能QQ通知,不能发放优惠券了么?还要全部都回滚。太不合常理了。

你苦思冥想,了解到了一个事件监听机制的方法,可以异步解耦,不正适合这个场景么。说干就干,代码重构走起。

事件监听解决方法

这里我就不说什么是事件监听机制了,概念百度一大把,我将从实际的例子说起,让你彻底理解这个机制是做什么的,什么时候用它。

我们先来定义一个支付事件类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 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;
}
}

支付服务类这么写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 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));
}
}

同样,当仓库监听到支付成功的事件,开始准备发货。