正文
小年之前分享了很多 MQ的文章,相信大家对消息中间件也很熟悉了。今天这篇呢,不聊别的,就想分享一个MQ简单且使用的干货。
先提个问题:不知道大家有没有这样的经历,MQ消费端的代码堆着各种各样的业务逻辑。随着业务需求增加,代码的逻辑也随着增加。有时候改动一点逻辑,又怕影响到其他业务,可谓是牵一发而动全身。
举个栗子吧:用户支付下单的业务场景。
用户发起支付,业务系统请求订单系统创建交易订单。一般来说,订单的交易处理会比较复杂和耗时,所以订单的支付结果通常都是异步返回的。要不就是异步回调,要不就是消息通知。
假设这里采用消息通知的方式,业务系统需要订阅相应的Topic进行处理。大致的代码实现如下(这里使用 RocketMQ 为例子来实现)
@RocketMQMessageListener(topic = "xxx", consumerGroup = "xxx")
public class OrderConsumer implements RocketMQListener<Order> {
@Override
public void onMessage(Order order) {
// 处理订单结果
handleOrder();
}
}
但如果业务需求要对不同类型的订单做不同的处理,比如分为充值订单、话费订单、购物订单等,不同类型的订单可能会有定制化的要求。
按照这种需求,我们一般可能会这么实现:
@RocketMQMessageListener(topic = "xxx", consumerGroup = "xxx")
public class OrderConsumer implements RocketMQListener<Order> {
@Override
public void onMessage(Order order) {
// 处理订单结果
if (order.getType() == 'recharge') {
}else if (order.getType() == 'shopping') {
}
...
}
}
没错,对订单的类型做 if else
的判断。一般来说如果类型不多,业务逻辑不复杂,这种方式足以解决了。但如果后面还有其他类型的拓展实现,且各类型的业务逻辑错综复杂,那么这个 Consumer 就会越来越臃肿,甚至有可能成为了祖传代码。而且其他分支的修改,有可能会影响整个的的逻辑。那就真的是,谁接盘谁头痛。
聪明的同学可能马上就想到对策,我用工厂方法 + 策略模式不就可以解决了吗?
这当然没毛病,确实可以解决上面所述的问题。但你以为就这么简单吗?小年今天分享的是另外一种更优雅的方式。
Spring 事件发布监听
Spring 事件发布监听,本质上来说是观察者模式的应用。
- ApplicationEvent:事件
- ApplicationEventPublisher:事件发布者
- ApplicationEventListenr:事件监听者
下面直接来看一下如何使用 Spring 事件发布解决上述的问题:
Consumer 中就不再有处理任何业务逻辑代码了,而是将消息包装成事件后,发布出去。
@RocketMQMessageListener(topic = "xxx", consumerGroup = "xxx")
public class OrderConsumer implements RocketMQListener<Order> {
@Autowired
private ApplicationContext applicationContext;
@Override
public void onMessage(Order order) {
// 事件发布
applicationContext.publishEvent(new OrderEvent(event));
}
}
// 定义事件
public class OrderEvent extends ApplicationEvent {
public OrderEvent(Order order) {
super(order);
}
public OrderEvent getSource() {
return (OrderEvent) super.getSource();
}
}
对不同的订单类型创建事件监听类,需要实现接口 ApplicationListener
:
@Component
public class RechargeOrderListener implements ApplicationListener<OrderEvent> {
@Override
public void onApplicationEvent(OrderEvent event) {
Order order = event.getSource();
if (order.getType = "recharge") {
// 充值订单处理
}
}
}
@Component
public class ShoppingOrderListener implements ApplicationListener<OrderEvent> {
@Override
public void onApplicationEvent(OrderEvent event) {
Order order = event.getSource();
if (order.getType = "shopping") {
// 购物订单处理
}
}
}
PS:也可以通过
@EventListener
注解的方式实现事件的监听。
显而易见,使用 Spring 事件发布机制后,原本需要在一个 Consumer 下写一大堆逻辑的,现在拆分成各个独立且不想互相影响的模块。
当然,按照上面贴出来的代码,事件监听者(Listener)还是需要根据 order.getType()
判断是否需要执行,似乎还是有点重复和繁琐。对有代码洁癖的小年来说,这当然是不能容忍的,于是再来一个魔法吧,模板方法
public abstract class AbstractOrderListener implements ApplicationListener<OrderEvent> {
@Override
public void onApplicationEvent(OrderEvent event) {
Order order = event.getSource();
if (getType().contains(order.getTransType())) {
onMessage(order);
}
}
public abstract void onMessage(OrderEvent order);
public abstract List<String> getType();
}
@Component
public class RechargeOrderListener extend AbstractOrderListener {
@Override
public void handleEvent(Order order) {
// 充值订单处理
}
}
至此,整个优化流程就差不多结束了。从原先 Consumer 堆砌所有业务代码,到现在模块化的拆分。看完之后,就一个字,爽!
普通的改变,将改变普通
我是宅小年,一个在互联网低调前行的小青年
关注公众号「宅小年」,个人博客 📖 edisonz.cn,阅读更多分享文章