spring事件解耦写法优化

spring事件解耦写法优化

1.概念

spring事件发布,是设计模式中观察者模式的实现,观察者模式建立一种对象与对象之间的关系,当一个目标对象发生改变时,由中间者通知一个或多个对象做出反应。一个观察目标可以对应多个观察者。而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。达到代码解耦的目的。

2.背景

以下是当前项目中对spring事件发布的写法。

// 更新借阅单状态
lendingReceiptDao.updateById(lendingReceipt);
// 发布借阅日志记录事件
publisher.publishEvent(new LendingReceiptLogEvent(LendingReceiptLogDto.builder()
        .lendingReceiptId(lendingReceipt.getLendingReceiptId())
        .opeBehavior(BizOpeBehaviorEnum.FOUND)
        .creatorName(userContext.getCurrentUserName())
        .creatorId(userContext.getCurrentUseId())
        .content("找回:" + reqVo.getRemark())
        .build()));

//中间逻辑省略....

// 更新色卡状态
colorCardDao.updateById(colorCard);
// 发布色卡日志记录事件
publisher.publishEvent(newColorCardLogEvent(Collections.singletonList(ColorCardLogDto
                .builder()
                .colorCardId(colorCard.getColorCardId())
                .creatorName(userContext.getCurrentUserName())
                .creatorId(userContext.getCurrentUseId())
                .opeBehavior(BizOpeBehaviorEnum.FOUND)
                .content(reqVo.getRemark())
                .businessSegment(BizSegmentEnum.STORE)
                .storeId(reqVo.getCurrentStoreId())
                .warehouseId(reqVo.getCurrentStoreId())
                .warehouseType(WarehouseTypeEnum.STORE.name())
                .build())));

// 刷新库存统计事件
publisher.publishEvent(new FlushInventoryEvent(InventoryDto.builder()
                .reviserName(userContext.getCurrentUserName())
                .reviserId(userContext.getCurrentUseId())
                .inventoryIds(Collections.singleton(colorCard.getInventoryId()))
                .build()));

2.1当前写法可能存在以下问题

  • 业务操作之后发布事件,发布事件代码与业务代码交叉,很难辨认中间是否遗漏事件的发布。
  • 事件传递参数过多,非影响性能情况下,建议只传必要参数。不然发送事件代码篇幅过长,影响业务代码的阅读。
  • 发布多个事件,多个事件也会导致发送的代码过长。

3.优化方案(伪代码实现)

  • 通过切面在dao层后置操作做事件发布,例如新增日志操作记录。这种前提是因为数据库增删改的时候引起的事件,且不适用jpa等泛型操作。目前也仅能做日志相关操作,因为持久层一般只做数据库相关的操作,设计业务的操作不应该放到该层中。
@PublishLogEventAfter
public void insert(LendingReceiptEntity lendingReceipt) {
    AssertUtil.isFalse(BeanUtil.isAllPropertyNull(lendingReceipt), "参数非法!");
    lendingReceiptMapper.insert(lendingReceipt);

}
@Component
@Aspect
public class PublishLogEventAfterAspect {
    
    @Around(value = "@annotation(publishLogEventAfter)")
    public void doServiceBefore(ProceedingJoinPoint pjp,PublishLogEventAfter publishLogEventAfter) {
        pjp.proceed();
        //获取参数
        Object[] args = pjp.getArgs();
        // 记录借阅日志
        publisher.publishEvent(new LendingReceiptLogEvent(args));
}
  • 通过helper层,将多个事件发布操作放在helper里面,由helper统一控制。
@Component
public class LendingEventPublishHelper {
    
    @Autowire
    ApplicationEventPublisher publisher;
    
    public void publish(Object... args) {
        // 记录借阅日志
        publisher.publishEvent(new LendingReceiptLogEvent(args));
        
        // 刷新借阅统计数据
        publisher.publishEvent(new LendingStatsEvent());
        
         // 刷新库存统计
        publisher.publishEvent(new FlushInventoryEvent());
}
  • 只发送一个业务事件,通过实现不同接口,使被对应的监听器消费。
public class LendingEvent extends ApplicationEvent implements FlushEvent, FlushStatEvent {
    /**
     * Create a new {@code ApplicationEvent}.
     *
     * @param source the object on which the event initially occurred or with
     *               which the event is associated (never {@code null})
     */
    public LendingEvent(Object source) {
        super(source);
    }
}
    @EventListener(classes = FlushEvent.class)
    public void flush(FlushEvent flushEvent) {
        System.out.println("FlushEvent事件处理中");
    }

    @EventListener(classes = FlushStatEvent.class)
    public void flush(FlushStatEvent flushStatEvent) {
        System.out.println("FlushStatEvent事件处理中");
    }
	@Test
    public void testEvent() {
        publisher.publishEvent(new LendingEvent(this));
    }

打印结果

FlushStatEvent事件处理中
FlushEvent事件处理中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值