开发者

Mybatis中拦截器的使用场景和技巧分享

目录
  • 场景描述
  • MyBATis拦截器
    • 锚定事件发生
    • 订阅事件
  • 观察者模式
    • 总结

      场景描述

      中小业务系统中,有时候会面临一些比较相http://www.devze.com似的业务场景。

      • XXX创建成功后,需要给XXX推送一条业务消息;
      • XXX更新的时候,需要给XXX推送一条业务提醒;
      • XXX创建OR更新的时候,需要将最新的数据推送到搜索引擎中,以方便其他业务系统在搜索引擎中能查询到;
      • XXX更新的时候,需要更新分布式缓存的XXX数据;
      • ……

      这些场景都有相似的特征,如下

      特征描述
      异步实际上与主流程关系不大,可以作为附属流程异步执行
      事务大多在事务结束之后执行
      并行可以串行执行,也可以并行执行,对最终结果影响不大

      Mybatis拦截器

      Mybatis提供了一些机制,www.devze.com可以允许我们在做数据库操作的时候进行我们额外的一些程序。当然,这看起来并没有JPA的EntityListener好用。

      但是通过这些机制,我们可以达成我们主要的目的,解耦合。(解耦合的好处显而易见,我们在关注主流程业务的时候,附属流程的业务也更容易扩展)

      下面是我们即将用到的一些简单概念,如下

      概念描述
      解耦解耦的本质就是将类之间的直接关系转换成间接关系
      观察者模式一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个“观察”该对象的其他对象。
      EventBus基于事件驱动,观察者们监听自己感兴趣的特定事件,进行相应的处理。

      锚定事件发生

      首先,我们要找到事件发生的地方,通常来说我们更愿意编程客栈在业务代码里写

      Company company = new Company();
      company.setCompanyName(companyName);
      companyMapper.insert(company);
      // 创建XXX成功后,触发了一些操作;
      DOSomething(company);
      

      但是,这种方式是耦合的,我们在doSomething() 里发生的一些异常会影响到主流程,而每一次增加附属流程的改动,都会产生影响范围的蔓延。

      这里,我们使用Mybatis提供的一种方式来锚定事件发生

      @Component
      @Intercepts( {
          @Signatur编程e(method = "update", type = Executor.class, args = {
              MappedStatement.class,
              Object.class
          })
      })
      public class EntityInterceptor implements Interceptor {
          private static final Logger LOGGER = LoggerFactory.getLogger(EntityInterceptor.class);
      
          @Override
          public Object intercept(Invocation invocation) throws Throwable {
              Object proceed = invocation.proceed();
              try {
                  Object[] args = invocation.getArgs();
                  MappedStatement ms = (MappedStatement) args[0];
                  Object params = args[1];
                  if (SqlCommandType.INSERT.equals(ms.getSqlCommandType())) {
                      insertCommond(params);
                  }
                  if (SqlCommandType.UPDATE.equals(ms.getSqlCommandType())) {
                      updateCommond(params);
                  }
              } catch (Exception e) {
                  LOGGER.warn("entity change warning: {}", e.getMessage());
              } finally {
                  return proceed;
              }
          }
          
              private void insertCommond(Object params) {
              if (Objects.isNull(params)) {
                  return;
              }
              // 插入Company的事件
              if (params www.devze.cominstanceof Company) {
                  Company company = (Company) params;
                  CompanyEvent companyEvent =
                      new CompanyEvent(CompanyEvent.TOPIC_ADD, WebUtils.getOpenId(), CompanyVo.from(company));
                  SpringUtil.getApplicationContext().publishEvent(companyEvent);
                  LOGGER.info("[发布事件:{}] - [事件内容:{}]", CompanyEvent.TOPIC_ADD, jsON.toJSONString(companyEvent));
              }
          }
      }
      

      在这里,我们监听了MybatisExecutor对象的update方法,来监听对象的新增和修改。

      package org.apache.ibatis.executor;
      
      public interface Executor {
      
        int update(MappedStatement ms, Object parameter) throws SQLException;
      }
      

      当 Company 的 insert 事件发生时,我们发布了一条 CompanyEvent 的事件。

      订阅事件

      我们使用发布-订阅模型实现了解耦合,针对刚才发布的 CompanyEvent 事件,我们来写一个事件消费者。

      @Component
      public class CompanyListener {
      
          /**
           * 监听事件 - 公司.
           *
           * @param companyEvent 事件.
           */
          @Lazy
          @Async
          @TransactionalEventListener(
              fallbackExecution = true,
              phase = TransactionPhase.AFTER_COMPLETION,
              classes = CompanyEvent.class)
          public void doAsync(CompanyEvent companyEvent) {
              LOGGER.info("[Company 订阅:{}] - [开始执行:{}]",
                  companyEvent.getTopic(), JSON.toJSONString(companyVo));
          }
      }
      

      代码中涉及到一些注解,简单介绍下

      注解介绍
      @Component会注册为Spring的一个Bean
      @Lazy该方法会异步执行
      @TransactionalEventListener在事务的不同阶段去触发执行该监听

      我们标注了该事件是在TransactionPhase.AFTER_COMPLETION(事务提交完成)这个事务节点进行事件处理。

      观察者模式

      上面使用了SpringEventListener来实现的事件驱动,除此之外,还可以使用GuavaEventBusVert.xEventBus等方式实现。

      很多工具类提供了关于EventBus的实现,但是使用逻辑和方式上大多大同小异。

      总结

      观察者模式监听模式都有利于解耦合,根据业务诉求合理的进行开发设计,能为以后的扩展打下坚实的基础。

      以上就是Mybatis中拦截器的使用场景和技巧分享的详细内容,更多关于Mybatis拦截器使用的资料请关注编程客栈(www.devze.com)其它相关文章!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜