背景
需求:第三方修改订单状态,不同状态有不同的业务逻辑。
例:状态=已接单,需要执行骑手分配业务;状态=打包完成,需要通知骑手来取餐业务;状态=派送完成,需要执行订单的数据统计...等等。
常规的可能就是多个if else根据不同的状态垒代码,随着业务的积累,需求叠加,最初的几个核心业务里面又会加不同的子业务...弊端逐渐显现,牵一发动全身!
然后就引出了标题的主角:事件驱动
介绍
我相信很多大佬看了上面的背景心里肯定乐了“呵~我用MQ不是也可以解决?”
是的,MQ也可以解决这个问题,但是技术是一把双刃剑, 会用不行,需要用好,各有优劣,需要我们根据业务作出取舍,这才是我们的价值。
Spring基于事件类EventObject和事件监听类ApplicationListener..实现了一套事件驱动模型,它类似于消息队列(MQ)中的 发布/订阅 模式,也类似于设计模式中的观察者模式。
通俗讲事件驱动就是,一件事的触发,相关的对应事也跟着触发了。
用户注册成功后,需要发短信,给新手大礼包,初始化权限等等操作。
事件驱动由三部分组成:
- 事件:用户可自定义事件类和相关属性及行为来表述事件特征。
- 事件发布者:在Spring中可通过ApplicationEventPublisher把事件发布出去,这样事件内容就可以被事件监听者处理。
- 事件监听者:ApplicationListener监听发布事件,处理事件发生之后的后续业务操作。
垒码
1、定义事件类和属性。(自Spring4.2之后定义事件不需要再显式继承ApplicationEvent类,直接定义一个bean即可,本文采用旧的)
//事件,显式继承 ApplicationEvent
public class OrderStatusEvent extends ApplicationEvent {
//订单修改的内容
public OrderStatusNoticeReq orderStatusNoticeReq;
//当前订单详情内容
public OrderInfo orderInfo;
public OrderStatusEvent(Object source) {
super(source);
}
}
2、事件发布。在对应的业务代码中进行事件的发布。
//应用事件发布器
@Autowired
private ApplicationEventPublisher publisher;
public void updateOrderStatus(OrderStatusNoticeReq req) {
OrderStatusEvent orderStatusEvent = new OrderStatusEvent(new Object());
orderStatusEvent.orderStatusNoticeReq = req;
// 透传最新订单数据
orderStatusEvent.orderInfo = orderInfo;
// 事件发布
publisher.publishEvent(orderStatusEvent);
}
在上述代码中,我们首先通过@Autowired注解将ApplicationEventPublisher接口注入到当前组件中。然后,在updateOrderStatus()方法中,我们首先查询订单信息,然后通过调publisher.publishEvent()方法来发布一个OrderStatusEvent事件,将orderInfo参数作为事件的数据传递。
最后,我们定义一个事件监听器,用于监听OrderEvent事件并执行相应的操作:
3、事件监听,可根据不同的业务建不同的监听类。
@Component
@Order(4)
@Slf4j
public class OrderChangeCompleteEventListener implements ApplicationListener<OrderStatusEvent> {
//@Async 表示异步处理,事件监听一般与事件发布者是解耦的,通过该注解异步处理监听内容。
@Async
@Override
public void onApplicationEvent(OrderStatusEvent event) {
OrderInfo orderInfo = event.orderInfo;
// 只处理完成订单
if (orderInfo.getOrderStatus() == OrderStatusEnum.COMPLETE.getValue()) {
insertKpi(orderInfo);
}
}
}
至此,代码已经搭好,可以根据需求进行拓展。
总结
其实,从上面来看,总体就是和MQ一样,发布和订阅,通过不同的条件执行不同的业务,如果不加条件,全部事件都处理。
合理的使用,能够很好的解耦我们的一些复杂业务,可以通过异步化执行避免不必要的开销,增强业务执行的效率,提高性能。
事件驱动能替代MQ吗?
答案是否定的,MQ可以实现异步、削峰、高可用.....是事件驱动所不能实现的。