掘金 后端 ( ) • 2024-06-10 15:46

前言

大家好我是大飞! 现在大环境不好了,防御式编程当然是现在必不可少的技能了,今天说一下防御式编程之事件发布机制。之前也写过一篇【关于事件发布机制源码浅析】的文章,如果之前还没了解过事件发布机制的同学可以看一下这篇文章,没有用过的可以先看一下我的这篇文章。之前简单介绍过事件发布机制,今天讲一下在实际情况中的运用需要注意哪些问题。`


一、使用场景

我的使用场景,最近做了一项目核心的业务都是审批流,事件流程的情况非常多,并且这次没有使用流程引擎。在项目开发结束之后,需要迭代一个待办的功能,就是流程到了哪个节点,就需要给节点的审批人发消息。这个时候我肯定不希望在以前的业务代码的里面写太多的逻辑代码,尽量不要影响以前的代码逻辑。这个时候我觉得引入spring boot的事件发布机制还不错,不排除后续还有其他需求引入进来。这样方便以后扩展把。

二、注意事项

1.降低业务代码和主流程逻辑的耦合度

我这次主要在审批业务中集成事件,代码逻辑已经十分复杂了。为了防止主流程业务逻辑再次复杂,我在业务代码的最后,进行事件的发布。处理事件的监听器肯定还需要很多参数,这些参数虽然可以从业务代码中传过去,但是这样就是在业务代码中写更多的逻辑。所以我们发布事件的时候就传递主要的参数,详细的参数就由各个监听器去处理吧。

  @Transactional(rollbackFor = Exception.class)
  @Override
  public void commitApproveRet(Long applyId) {
    Apply apply = baseMapper.selectById(applyId);
    ..................................
    ...................................
    baseMapper.updateById(apply);
    processRoster(nextOrCutNode);
    //发布事件
    applicationContext.publishEvent(NextApproveEvent.initEvent(apply,nextOrCutNode);
  }

2.是否需要在同一个事物、是否需要进行异步处理

实际开发中还需要特别注意事件监听器的逻辑 是否需要和主流程保持在同一事物中,以及是否使用多线程进行异步处理。

目前我的业务场景,适合异步操作。但是异步的前提我的业务逻辑的事物已经完成提交了。因为我是直接用注解开启的事物,所以我想在监听器里面执行数据库查询的时候还不能使用多线程。所以我监听器的处理逻辑,是在数据库操作完成之后,再开启的多线程进行处理。

  @EventListener
  public void approvedEventListener(NextApproveEvent event){
    log.info("-------------发送完成代办消息----------");
    try{
      List<ToDo> list = handleData(event);
      executor.execute(()->{
      SendToDoUtils.sendMsg(list);
      ));
    }catch (Exception e){
      log.error("发送完成待办消息出错:{}",JSON.toJSONString(event),e);
    }
  }

在使用事件发布机制的时候,我们要在业务上确定,监听事件的处理逻辑和主流程是否要进行强绑定;如果需要就必须保证在同一事务中。我在业务系统的开发过程,几乎都不需要要强绑定。不需要强绑定的情况,在事件处理的时候就可以进行异步处理,提高程序响应速度,或者捕捉异常,防止事务回滚影响正常业务。当然如果是业务上需要进行强绑定,就必须保证在同一事务下,就不要捕捉异常,防止事务不能回滚。

三、总结

做了六年的java开发了,在业务开发中比较难受的就是维护别的代码,特别是那种不写注释,还滥用设计模式的代码了。能在业务代码中用设计模式的大多都是为了学习而写的,所以是为写设计模式而使用设计模式罢了。 比如我们用的事件发布机制(观察模式),一个事件可以实现多个监听器,多个监听处理的业务逻辑不一样,可能有些业务需要和主流程进行同步处理,可能有些有是异步处理,异步处理时候,我事务还没提交就去读取数据,或者修改数据等问题。如果在开发中,不去考虑这些问题,可能在测试中还不会发现问题,发布到生产之后就会出各种问题。当然我还是鼓励大家在实际开发中,大胆使用,大胆探索,提升自我实力才是王道!