• 九、插件


    • MyBatis在四大对象的创建过程中,都会有插件进行 介入。插件可以利用动态代理机制一层层的包装目标对象,而实现在目标对象执行目标方法之前进行拦截 的效果。

    • MyBatis允许在已映射语句执行过程中的某一点进行 拦截调用。

    • 默认情况下,MyBatis允许使用插件来拦截的方法调 用包括:

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

    一、插件开发步骤

    • 编写插件实现Interceptor接口,并使用 @Intercepts注解完成插件签名。

    /**
     * 完成插件签名:
     *        告诉MyBatis当前插件用来拦截哪个对象的哪个方法
     */
    @Intercepts({
            @Signature(type= StatementHandler.class,method="parameterize",args=java.sql.Statement.class)
    })
    public class FirstPlugin implements Interceptor {}
    • 在全局配置文件中注册插件
    <!--plugins:注册插件  -->
        <plugins>
            <plugin interceptor="com.jdy.mybatis2020.MyPlugin.FirstPlugin">
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </plugin>
            <plugin interceptor="com.jdy.mybatis2020.MyPlugin.FirstPlugin"></plugin>
        </plugins>

    二、插件原理

    • 按照插件注解声明,按照插件配置顺序调用插件plugin方 法,生成被拦截对象的动态代理。

    • 多个插件依次生成目标对象的代理对象,层层包裹,先声 明的先包裹;形成代理链。

    • 目标方法执行时依次从外到内执行插件的intercept方法。

    • 多个插件情况下,我们往往需要在某个插件中分离出目标 对象。可以借助MyBatis提供的SystemMetaObject类来进行获 取最后一层的h以及target属性的值。

    三、Interceptor接口

    • Intercept:拦截目标方法执行

    • plugin:生成动态代理对象,可以使用MyBatis提 供的Plugin类的wrap方法

    • setProperties:注入插件配置时设置的属性

    /**
     * 完成插件签名:
     * 告诉MyBatis当前插件用来拦截哪个对象的哪个方法
     */
    @Intercepts({
            @Signature(type = StatementHandler.class, method = "parameterize", args = java.sql.Statement.class)
    })
    public class FirstPlugin implements Interceptor {
    
        /**
         * 拦截目标方法执行
         *
         * @param invocation
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            // TODO Auto-generated method stub
            System.out.println("MyFirstPlugin...intercept:" + invocation.getMethod());
            //动态的改变一下sql运行的参数:以前1号员工,实际从数据库查询3号员工
            Object target = invocation.getTarget();
            System.out.println("当前拦截到的对象:" + target);
            //拿到:StatementHandler==>ParameterHandler===>parameterObject
            //拿到target的元数据
            MetaObject metaObject = SystemMetaObject.forObject(target);
            Object value = metaObject.getValue("parameterHandler.parameterObject");
            System.out.println("sql语句用的参数是:" + value);
            //修改完sql语句要用的参数
            metaObject.setValue("parameterHandler.parameterObject", 11);
            //执行目标方法
            Object proceed = invocation.proceed();
            //返回执行后的返回值
            return proceed;
        }
    
        /**
         * 生成动态代理对象,可以使用MyBatis提 供的Plugin类的wrap方法
         *
         * @param target
         * @return
         */
        @Override
        public Object plugin(Object target) {
            // TODO Auto-generated method stub
            //我们可以借助Plugin的wrap方法来使用当前Interceptor包装我们目标对象
            System.out.println("MyFirstPlugin...plugin:mybatis将要包装的对象" + target);
            Object wrap = Plugin.wrap(target, this);
            //返回为当前target创建的动态代理
            return wrap;
        }
    
        /**
         * 注入插件配置时设置的属性
         *
         * @param properties
         */
        @Override
        public void setProperties(Properties properties) {
            // TODO Auto-generated method stub
            System.out.println("插件配置的信息:" + properties);
        }
    }

      常用代码:从代理链中分离真实被代理对象

    //1、分离代理对象。由于会形成多次代理,所以需要通过一个 while 循环分离出最终被代理对象,从而方便提取信息
    MetaObject metaObject = SystemMetaObject. forObject(target);
    while (metaObject.hasGetter("h")) {
            Object h = metaObject.getValue("h"); 
          metaObject = SystemMetaObject. forObject(h);
    }
    //2、获取到代理对象中包含的被代理的真实对象 
    Object obj = metaObject.getValue("target");
    //3、获取被代理对象的MetaObject方便进行信息提取 
    MetaObject forObject = SystemMetaObject.forObject(obj);
  • 相关阅读:
    系统学习(javascript)_基础(语法)
    系统学习(javascript)_基础(数据类型之间的转换)
    系统学习(javascript)_基础(数据类型一)
    npm_一个有意思的npm包
    java_环境安装(window10)
    window10_使用技巧
    剑指Offer_编程题_16
    剑指Offer_编程题_15
    剑指Offer_编程题_14
    剑指Offer_编程题_13
  • 原文地址:https://www.cnblogs.com/jdy1022/p/14202192.html
Copyright © 2020-2023  润新知