关于mybatis:mybatisPlus-拦截器执行源码

57次阅读

共计 2884 个字符,预计需要花费 8 分钟才能阅读完成。

通过 MyBatis 提供的弱小机制,应用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦挡的办法签名即可。

     @Slf4j
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
        ),
        @Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class}
        ),
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}
        ),
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}
        ),
})
@Component
@Order(-2)
public class CustomizeInterceptor implements Interceptor {
    @Override
    public Object plugin(Object target) {return Plugin.wrap(target, this);
    }
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取代理对象
        log.info("拦挡:{}", invocation.getMethod().getName());
        return invocation.proceed();}
}

  1. MybatisConfiguration 中源码解析办法
     public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        executorType = executorType == null ? defaultExecutorType : executorType;
        executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
        Executor executor;
        if (ExecutorType.BATCH == executorType) {executor = new MybatisBatchExecutor(this, transaction);
        } else if (ExecutorType.REUSE == executorType) {executor = new MybatisReuseExecutor(this, transaction);
        } else {executor = new MybatisSimpleExecutor(this, transaction);
        }
        if (cacheEnabled) {executor = new MybatisCachingExecutor(executor);
        }
        // 插件拦截器链
        executor = (Executor) interceptorChain.pluginAll(executor);
        return executor;
        }
        }
    
  1. InterceptorChain 中拦截器链条
     private final List<Interceptor> interceptors = new ArrayList<>();
      public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {
        // 调用
          target = interceptor.plugin(target);
        }
        return target;
      }
      // 调用接口
      default Object plugin(Object target) {return Plugin.wrap(target, this);
    }

3. 它又持续调用了 Plugin 的静态方法 wrap

   public static Object wrap(Object target, Interceptor interceptor) {
   // 获取签名办法
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
    // 生成代理对象 动静代理 调用 invoke
      return Proxy.newProxyInstance(type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }
      

4. 执行 拦挡

   @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {Set<Method> methods = signatureMap.get(method.getDeclaringClass());
      if (methods != null && methods.contains(method)) {
      // 调用拦挡办法
        return interceptor.intercept(new Invocation(target, method, args));
      }
      return method.invoke(target, args);
    } catch (Exception e) {throw ExceptionUtil.unwrapThrowable(e);
    }
  }    
  1. 流程图

最终 Executor 不再是原来的类,而是它的代理类。newStatementHandler 办法和 newResultSetHandler 办法的流程,也差不多,最终也是生成代理类

6. 当 Executor、StatementHandler、ParameterHandler、ResultSetHandler 执行他们本人的办法时,实际上调用他们的代理类 Plugin 中的 invoke 办法

7. 多个 plugins 拦截器代理 后面的代理类被前面的拦截器又代理
套娃行为

所以,前面的将会代理后面的,——越外层的越先执行

8. 多个插件的执行程序曾经明了了,那么插件外面办法的执行程序呢?

query->prepare->setParameters->handleResultSets

这个博客还是讲的很分明的

参考博客:https://blog.csdn.net/qq_18433441/article/details/84036317

正文完
 0