通过 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


Redorblack
39 声望0 粉丝

后端菜鸟记录美好生活