likes
comments
collection
share

Spring Events——事件监听机制

作者站长头像
站长
· 阅读数 27

背景

高内聚低耦合,一直是我们软件开发者提倡的开发准则,然而在日常的开发中,产品日益迭代,代码堆砌、未及时小范围重构等,耦合性愈见严重。其实在日常的功能当中也可以做优雅的解耦。

常见的电商商会员注册场景:

  1. 注册新用户
  2. 优惠券和折扣:为新注册用户提供优惠券或折扣码,鼓励他们进行首次购买
  3. 积分奖励:引入积分系统,新用户注册后可以获得一定的积分,积分可以在未来的购物中使用,以此来增加用户的粘性
  4. 推荐奖励:实施推荐系统,当现有用户推荐新用户成功注册时,双方都可以获得一定的奖励,如优惠券、积分等
  5. 会员专属内容:提供会员专属的内容或服务,如会员专属的产品预览、特殊折扣日等,增加会员的专属感和归属感
  6. ...

可以看到,我们在注册会员这一个动作之后,常常需要多个地方关注这个动作。

当然,我们可以用组合模式,然后在注册会员这个方法内,调用不同功能,比如:

    /**
     * 注册会员
     */
    public void registerMember(RegisterParam param) {
        // 参数校验
        checkParam(param);

        // 注册会员
        registerService.register(param);

        // 优惠券发放
        couponService.grantCoupon(param);

        // 积分奖励
        pointService.awardPoint(param);

        // ...
    }

以上组合模式虽然代码也非常清晰(功能、职责),比直接在一个方法写所有逻辑要好很多。

但是,随着后期产品的迭代,我们的需求可能有 内部人员推荐、会员专属 内容等,然后继续在这一段完善功能:

    /**
     * 注册会员
     */
    public void registerMember(RegisterParam param) {
        // 参数校验
        checkParam(param);

        // 注册会员
        registerService.register(param);

        // 优惠券发放
        couponService.grantCoupon(param);

        // 积分奖励
        pointService.awardPoint(param);

        // 推荐奖励
        recommendService.awardRecommend(param);

        // 会员专属内容
        memberContentService.sendContent(param);

        // ...
    }

你也看到了,如果继续产品迭代,可能会继续在 registerMember 做更多操作,这将存在几个明显的缺点:

  1. registerMember 方法臃肿,耦合严重,也并不满足单一职责
  2. 如果后续注册会员的需求频繁变更,相应就需要频繁变更 registerMember 方法,违反了开闭原则

:有没有更好的方法解决呢?

当然有,观察者模式你一定不陌生,我们将注册会员这一行为以事件的形式发布出去,相关观察者监听到这一行为并进行处理,如下图:

Spring Events——事件监听机制

  1. 首先,先处理与注册会员相关的主逻辑
  2. 然后,将发布 注册会员事件,由相关监听者处理对应业务逻辑。

这样一来,即使后续功能迭代需要新增业务处理,我们可以很方便扩展监听者 listener,符合 单一职责开闭原则

:在 Spring 环境下,我们需要自定义观察者机制吗?

不用,Spring 有现成的的事件监听机制,符合我们当前的场景,接下来看看事件监听机制是如何处理~

实践

1、首先我们将会员注册定义为一个独立的事件:

public class RegisterMemberEvent extends ApplicationEvent {

    private RegisterMemberInfo registerMemberInfo;

    public RegisterMemberEvent(Object source) {
        super(source);
    }

    public RegisterMemberEvent(Object source, RegisterMemberInfo registerMemberInfo) {
        super(source);
        this.registerMemberInfo = registerMemberInfo;
    }

    public RegisterMemberInfo getRegisterMemberInfo() {
        return registerMemberInfo;
    }
    
}

2、定义监听器

普通用法: 以发送积分奖励监听者为例

@Component
public class RegisterMemberListener implements ApplicationListener<RegisterMemberEvent> {
    @Override
    public void onApplicationEvent(RegisterMemberEvent event) {
        // 积分奖励
        awardPoint(param);
        
        // 发送短信
        sendSms(param);
        
        // ...
    }
}

当然,也可以直接用注解的形式:

public class RegisterMemberListener {

    @EventListener(classes = RegisterMemberEvent.class)
    @Order(0)
    @Async
    public void awardPoint(RegisterMemberEvent event) {

    }

    @EventListener(classes = RegisterMemberEvent.class)
    @Order(0)
    @Async
    public void sendSms(RegisterMemberEvent event) {

    }

}

3、事件发布

@Service
public class RegisterMemberService {

    @Resource
    private ApplicationEventPublisher applicationEventPublisher;

    public void register() {
        // 参数校验
        checkParam(param);

        // 注册会员
        registerService.register(param);

        applicationEventPublisher.publishEvent(new RegisterMemberEvent(this, new RegisterMemberInfo()));

    }

}

至此,我们就优雅的解决了以上问题,接下来我们分析下 spring 事件监听机制原理。

小结

Spring ApplicationEvent 本质也是采用的观察者模式进行解耦设计,其内置了部分 Event 在 Spring 框架内部使用;

同时,我们也可以很灵活的定义业务层的事件类型,扩展性强,符合高内聚、低耦合特性。

尤其在一些复杂的业务场景下,对于功能解耦、后期扩展等都有很强的实用价值!

转载自:https://juejin.cn/post/7377662459920203813
评论
请登录