如何基于Spring中的事件驱动编程实现业务解耦?ApplicationEventPublisher

文章介绍了事件驱动在处理订单状态变更业务中的应用,以减少大量ifelse带来的问题。通过Spring的事件发布和监听机制,实现了类似MQ的发布/订阅模式,简化了代码结构。事件驱动包括事件、事件发布者和事件监听者三个部分,适用于用户注册后的关联操作。然而,事件驱动并不能替代MQ,因为MQ提供了异步、削峰等更多功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

需求:第三方修改订单状态,不同状态有不同的业务逻辑。

例:状态=已接单,需要执行骑手分配业务;状态=打包完成,需要通知骑手来取餐业务;状态=派送完成,需要执行订单的数据统计...等等。

常规的可能就是多个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可以实现异步、削峰、高可用.....是事件驱动所不能实现的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值