模拟MyBatis插件的执行过程

MyBatis插件

插件概述

MyBatis允许用户自定义拦截器允许拦截:

  1. Executor类里的update() query() commit()等方法
  2. ParameterHanlder类里的getParameterObject() setParameters()等方法
  3. ResultSetHandler类里的handleResultSets()、handleOutputParameters()等方法
  4. StatementHandler类里的prepare()、query()等方法。
    实现用户自定义的一些功能,对sql、参数、执行结果做其他处理,比如分页功能。

如何使用

继承Interceptor接口

@Intercepts({
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
public class MapUnderScoreToCamelCasePlugin implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
	   Object o = invocation.proceed();
       return o;
    }
}

配置插件

<plugins>
        <plugin interceptor="com.sss.plugins.paging.PageInterceptor">
            <property name="dbType" value="mysql"/>
            <property name="dialect.oracle" value="com.sss.plugins.paging.OracleDialect"/>
            <property name="dialect.mysql" value="com.sss.plugins.paging.MySQLDialect"/>
        </plugin>
		<plugin interceptor="com.sss.plugins.ShowSqlPlugin"></plugin>
		<plugin interceptor="com.sss.plugins.MapUnderScoreToCamelCasePlugin"></plugin>
    </plugins>

模拟MyBatis插件的原理

Interceptor

自定义的Plugin要实现Interceptor接口,其中intercept()方法要在动态代理的invoke()方法中调用,出发自定义Plugin中的业务逻辑。

public interface Interceptor {

  Object intercept(Invocation invocation) throws Throwable;

  default Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }
}

InterceptorChain

该类将目标Target对象,循环包装,调用Plugins.wrap()方法生成动态代理对象。

public class InterceptorChain {

  private final List<Interceptor> interceptors = new ArrayList<>();

  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

  public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
  }

  public List<Interceptor> getInterceptors() {
    return Collections.unmodifiableList(interceptors);
  }

}

Invocation

Invocation对象暴露给Plugin类,共插件拿到需要的参数自己做处理。

public class Invocation {

  private final Object target;
  private final Method method;
  private final Object[] args;

  public Invocation(Object target, Method method, Object[] args) {
    this.target = target;
    this.method = method;
    this.args = args;
  }

  public Object getTarget() {
    return target;
  }

  public Method getMethod() {
    return method;
  }

  public Object[] getArgs() {
    return args;
  }

  public Object proceed() throws InvocationTargetException, IllegalAccessException {
    return method.invoke(target, args);
  }
}

Plugin

Plugin类里实现了动态代理的invoke方法。

public class Plugin implements InvocationHandler {

  private final Object target;
  private final Interceptor interceptor;

  private Plugin(Object target, Interceptor interceptor) {
    this.target = target;
    this.interceptor = interceptor;
  }

  public static Object wrap(Object target, Interceptor interceptor) {
    Class<?> type = target.getClass();
    Class<?>[] interfaces = getAllInterfaces(type);
    if (interfaces.length > 0) {
      return Proxy.newProxyInstance(
        type.getClassLoader(),
        interfaces,
        new Plugin(target, interceptor));
    }
    return target;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    return interceptor.intercept(new Invocation(target, method, args));
  }

  private static Class<?>[] getAllInterfaces(Class<?> type) {
    Set<Class<?>> interfaces = new HashSet<>();
    while (type != null) {
      for (Class<?> c : type.getInterfaces()) {
        interfaces.add(c);
      }
      type = type.getSuperclass();
    }
    return interfaces.toArray(new Class<?>[interfaces.size()]);
  }
}

调用方

public class Test {
  public static void main(String[] args) {
    InterceptorChain interceptorChain = new InterceptorChain();
    interceptorChain.addInterceptor(new Plugin1());
    interceptorChain.addInterceptor(new Plugin2());
    Executor e = (Executor) interceptorChain.pluginAll(new SimpleExecutor());
    e.query();
  }
}

interface Executor{
  void query();
}

class SimpleExecutor implements Executor{
  public void query(){
    System.out.println("做一些查询");
  }
}

class Plugin1 implements Interceptor{
  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    System.out.println("插件一拦截");
    return invocation.proceed();
  }
}


class Plugin2 implements Interceptor{
  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    System.out.println("插件二拦截");
    return invocation.proceed();
  }
}

运行结果

在这里插入图片描述
debug可以看到:
最后拿到的Executor e其实是对目标target(SimpleExecutor类)嵌套了2层动态代理。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值