Mybatis Plugin插件

Plugin

首先mybatisPlugin是针对于mybatis四大组件(Statementhandler、resultsethandler、parameterHandler、executor)做增强操作的。
MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。
以pageHlper拦截器为例

@SuppressWarnings("rawtypes")
@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class PageHelper implements Interceptor

根据注解构建signatureMap

private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
    Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
    // issue #251
    if (interceptsAnnotation == null) {
      throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
    }
    Signature[] sigs = interceptsAnnotation.value();
    Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
    for (Signature sig : sigs) {
      Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>());
      try {
        Method method = sig.type().getMethod(sig.method(), sig.args());
        methods.add(method);
      } catch (NoSuchMethodException e) {
        throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
      }
    }
    return signatureMap;
  }

key为自定义拦截器接口 ,参数时是方法参数
多个拦截器就会代理多次,对代理类再进行代理。

public interface Interceptor {
//执行目标方法
Object intercept(Invocation invocation) throws Throwable;
//执行pluginAll调用
Object plugin(Object target);
//xml配置的初始化参数值
void setProperties(Properties properties);
}

我们要实现逻辑的方法是intercept
对于plugin方法,可以自定义一些场景

 @Override
    public Object plugin(Object target) {
        if (target instanceof Executor) {
            return Plugin.wrap(target, this);
        }
        return target;

    }

例子

@Intercepts({@Signature(type = Executor.class, method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
  public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Object parameterObject = null;
        try {

             parameterObject = args[1];
        }catch (Exception e){
            System.out.println(e);
        }
        // id为执行的mapper方法的全路径名,如com.mapper.UserMapper
        String id = ms.getId();
        String sqlCommandType = ms.getSqlCommandType().toString();
        if (!sqlCommandType.equals(SqlCommandType.SELECT.toString())) {
            return invocation;
        }
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        String origSql = boundSql.getSql();
        String newSql = getNewSql(id, origSql);
        if (newSql.equals(origSql)) {
            return invocation;
        }
        // 重新new一个查询语句对象
        BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), newSql,
                boundSql.getParameterMappings(), boundSql.getParameterObject());

        // 把新的查询放到statement里
        MappedStatement newMs = newMappedStatement(ms, new BoundSqlSqlSource(newBoundSql));
        for (ParameterMapping mapping : boundSql.getParameterMappings()) {
            String prop = mapping.getProperty();
            if (boundSql.hasAdditionalParameter(prop)) {
                newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));
            }
        }

        Object[] queryArgs = invocation.getArgs();
        queryArgs[0] = newMs;
        logger.info("由于数据权限,SQL被改写 originSql: {},newSql: {}", origSql, newSql);
        return invocation;
    }

获取查询sql并改写

原理分析

再创建四大核心对象时会对对象做代理操作
例如
![image.png](https://img-blog.csdnimg.cn/img_convert/52d370b36badb80659bc7efe791f144e.png#clientId=u30d5b9a5-e98a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=515&id=ub7d803a1&margin=[object Object]&name=image.png&originHeight=772&originWidth=1181&originalType=binary&ratio=1&rotation=0&showTitle=false&size=93254&status=done&style=none&taskId=udbc4c837-4a55-4a70-8932-6d854c219a4&title=&width=787.3333333333334)
代理类Plugin

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) {
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }


  private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
    Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
    // issue #251
    if (interceptsAnnotation == null) {
      throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
    }
    Signature[] sigs = interceptsAnnotation.value();
    Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
    for (Signature sig : sigs) {
      Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>());
      try {
        Method method = sig.type().getMethod(sig.method(), sig.args());
        methods.add(method);
      } catch (NoSuchMethodException e) {
        throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
      }
    }
    return signatureMap;
  }


wrap方法会根据注解信息选择性的进行代理操作

package org.apache.ibatis.plugin;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.ibatis.reflection.ExceptionUtil;

/**
 * @author Clinton Begin
 */
public class Plugin implements InvocationHandler {


  @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);
    }
  }

}


内部逻辑就是获取签名信息,执行时。匹配目标方法和注解中的方法参数,如果匹配上,那么执行拦截器interceptor。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
freemybatisplugin是一个用于MyBatis框架的插件,它可以简化MyBatis开发过程中的一些繁琐操作,让开发者更加高效地使用MyBatis。 要下载freemybatisplugin插件,首先需要打开浏览器,并进入freemybatisplugin的官方网站。在网站上,我们可以找到插件的下载链接。下载过程中可能需要提供一些基本的个人信息,例如邮箱地址等。 一旦下载完成,我们可以将插件文件(一般为jar文件)保存到合适的位置。接下来,需要将插件添加到我们所使用的IDE中。具体的添加方式根据不同的IDE而有所不同。 例如,对于IntelliJ IDEA这样的IDE,可以通过以下步骤添加插件: 1. 打开IDE,并进入“设置”菜单。 2. 在设置菜单中,找到“插件”选项。 3. 在插件选项中,找到“安装插件”按钮,并点击它。 4. 在弹出的文件选择窗口中,找到并选中之前下载的freemybatisplugin插件文件。 5. 点击“确定”按钮,开始安装插件。 6. 安装完成后,IDE会提示重启,点击“重启”按钮。 完成以上步骤后,freemybatisplugin插件就已经成功添加到IDE中了。接下来,我们可以在开发过程中使用插件提供的功能了。例如,插件可以帮助我们自动生成MyBatis的XML文件和Mapper接口,简化了繁琐的配置过程。 总之,通过以上步骤,我们可以方便地下载并安装freemybatisplugin插件,从而提高MyBatis开发的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值