• mybatis自定义插件


    15.0 自定义插件

    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 接口,并指定想要拦截的类,方法,参数(由于有多态的情况)即可

    // ExamplePlugin.java
    @Intercepts({
        @Signature(
            type= Executor.class,
            method = "update",
            args = {MappedStatement.class,Object.class})})
    public class ExamplePlugin implements Interceptor {
      private Properties properties = new Properties();
      public Object intercept(Invocation invocation) throws Throwable {
        // implement pre processing if need
        Object returnObject = invocation.proceed();
        // implement post processing if need
        return returnObject;
      }
      public void setProperties(Properties properties) {
        this.properties = properties;
      }
    }
    
    
      
        
      
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    上面的插件将会拦截在 Executor 实例中所有的 “update” 方法调用, 这里的 Executor 是负责执行底层映射语句的内部对象。

    注意:

    这四大类中方法具体可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码。 如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。 因为在试图修改或重写已有方法的行为时,很可能会破坏 MyBatis 的核心模块。 这些都是更底层的类和方法,所以使用插件的时候要特别当心。

    MyBatis官方文档中也有这样的说明:

    MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

    Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
    ParameterHandler (getParameterObject, setParameters)
    ResultSetHandler (handleResultSets, handleOutputParameters)
    StatementHandler (prepare, parameterize, batch, update, query)

    在MyBatis的四大对象创建的过程中,每个对象的创建后都不是直接返回的,而是要经过一个拦截器链进行包装后返回:

    executor = (Executor) interceptorChain.pluginAll(executor);
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    下面查看InterceptorChain类中的pluginAll方法:

    public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
    target = interceptor.plugin(target);
    }
    return target;
    }
    形参Object target,这个是Executor、ParameterHandler、ResultSetHandler、StatementHandler接口的实现类,换句话说,plugin方法是要为Executor、ParameterHandler、ResultSetHandler、StatementHandler的实现类生成代理,从而在调用这几个类的方法的时候,其实调用的是InvocationHandler的invoke方法。

    插件用的是责任链模式,责任链模式是一种对象行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链,请求在这个链上传递,直到链上的某一个对象决定处理此请求。

    责任链模式讲解

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SejyTzvj-1669338504017)(https://gimg2.baidu.com/image_search/src=http%3A%2F%2Ftva1.sinaimg.cn%2Flarge%2F00831rSTly1gdaind2f9sj31eg0mk0uv.jpg&refer=http%3A%2F%2Ftva1.sinaimg.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671860091&t=e27fa2f65afedbfc80224d5ab7e66fe8)]

    MyBatis接口

    /**

    • @author Clinton Begin
      */
      public interface Interceptor {

    Object intercept(Invocation invocation) throws Throwable;

    Object plugin(Object target);

    void setProperties(Properties properties);

    }

    intercept:它将直接覆盖你所拦截的对象,有个参数Invocation对象,通过该对象,可以反射调度原来对象的方法;
    plugin:target是被拦截的对象,它的作用是给被拦截对象生成一个代理对象;
    setProperties:允许在plugin元素中配置所需参数,该方法在插件初始化的时候会被调用一次;

    简单的说,mybatis插件就是对ParameterHandler、ResultSetHandler、StatementHandler、Executor这四个接口上的方法进行拦截,利用JDK动态代理机制,为这些接口的实现类创建代理对象,在执行方法时,先去执行代理对象的方法,从而执行自己编写的拦截逻辑,所以真正要用好mybatis插件,主要还是要熟悉这四个接口的方法以及这些方法上的参数的含义;

    另外,如果配置了多个拦截器的话,会出现层层代理的情况,即代理对象代理了另外一个代理对象,形成一个代理链条,执行的时候,也是层层执行;

    关于mybatis插件涉及到的设计模式和软件思想如下:

    1. 设计模式:代理模式、责任链模式;

    2. 软件思想:AOP编程思想,降低模块间的耦合度,使业务模块更加独立;

    一些注意事项:

    1. 不要定义过多的插件,代理嵌套过多,执行方法的时候,比较耗性能;

    2. 拦截器实现类的intercept方法里最后不要忘了执行invocation.proceed()方法,否则多个拦截器情况下,执行链条会断掉;

  • 相关阅读:
    手写promis(2)-- 链式编程篇
    Java注释
    uni-app 、Spring Boot 、ant Design 打造的一款跨平台包含小说(仿真翻页、段落听书)、短视频、壁纸等功能含完备后台管理的移动应用
    一份Java学习笔记送给大家
    《深入了解java虚拟机》高效并发读书笔记——Java内存模型,线程,线程安全 与锁优化
    Error response from daemon: Get https://registry-1.docker.io/v2/
    匈牙利算法 -- Acwing 861. 二分图的最大匹配
    如何重置iPhone的网络设置?这里提供详细步骤
    [附源码]java毕业设计游戏战队考核系统
    ABC350 FG 题解
  • 原文地址:https://blog.csdn.net/dongdongdongJL/article/details/128031806