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)

 

二、插件开发步骤

插件开发步骤

– 1)、编写插件实现Interceptor接口,并使用@Intercepts注解完成插件签名

– 2)、在全局配置文件中注册插件

 

<plugins>
    <!--这两个自己定义的插件:-->
    <plugin interceptor="com.mybatis.plugin.MyFirstPlugin">
        <property name="userName" value="root"/>
        <property name="password" value="132456"/>
    </plugin>
    <plugin interceptor="com.mybatis.plugin.MySecondPlugin">

    </plugin>

    <!-- com.github.pagehelper为PageHelper类所在包名 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
        <property name="param1" value="value1"/>
    </plugin>
</plugins>
@Intercepts({
        @Signature(type = StatementHandler.class,method = "parameterize",args=Statement.class)
}
)
public class MyFirstPlugin implements Interceptor {

    /**
     * 拦截的方式
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("MyFirstPlugin....拦截的方法intercept:"+invocation.getMethod());
        //执行方法,放行** 实际实行是这里的方法执行目标方法

        Object target = invocation.getTarget();

        MetaObject metaObject = SystemMetaObject.forObject(target);
        System.out.println("first拦截器的参数"+metaObject.getValue("parameterHandler.parameterObject"));
        metaObject.setValue("parameterHandler.parameterObject", 4);
        Object proceed = invocation.proceed();
        return proceed;
    }

    /**
     * 创建包装类,也就是代理对象
     * 包装目标对象的:包装:为目标对象创建一个代理对象
     * @param target
     * @return
     */
    @Override
    public Object plugin(Object target) {
        //我们可以借助Plugin的wrap方法来使用当前Interceptor包装我们目标对象
        System.out.println("MyFirstPlugin...plugin:mybatis将要包装的对象"+target);
        Object wrap = Plugin.wrap(target, this);
        //返回为当前target创建的动态代理
        return wrap;
    }

    /**
     *setProperties:
     * 	 * 		将插件注册时 的property属性设置进来
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件配置的信息:"+properties);
    }
}

@Intercepts({
        @Signature(type = StatementHandler.class,method = "parameterize",args=Statement.class)
})
public class MySecondPlugin implements Interceptor {


    /**
     * 这段代码的意图就是理解运行过程
     * 首先配置的插件是first 然后是second
     * 所有在生成代理对象的时候会吃产生多级代理,并且最里面的事真是的被代理对象,然后是first代理对象,然后是secode代理对象
     *
     * 但是在执行的时候是外面的second代理对象先执行设置参数的,这里的代码获取的参数就是测试方法传递的2,然后通过while循环,找到最里面的被代理对象
     * 将参数更改为5,执行设置参数,放行后开始执行first的插件,此时获取的目标对象参数是5,经过更改然后改为4,最后执行的就是查询4号员工的信息
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("MySecondPlugin....intercept:"+invocation.getMethod());

        //动态改变传入的参数,以前运行的事1号员工,现在改为3号员工
        //被拦截的对象
        Object target = invocation.getTarget();
        System.out.println("被拦截的目标对象是:"+target);
        //获取目标对象的原始数据
//        MetaObject metaObject = SystemMetaObject.forObject(target);

        //拿到:StatementHandler==>ParameterHandler===>parameterObject
//        Object value = metaObject.getValue("parameterHandler.parameterObject");
//        System.out.println("sql语句用的参数是:"+value);
        //修改完sql语句要用的参数
//        metaObject.setValue("parameterHandler.parameterObject", 3);
        //执行目标方法




        /*******************while 循环分离出最终被代理对象,从而方便提取信息*******************************/

//1、分离代理对象。由于会形成多次代理,所以需要通过一个

        MetaObject metaObject = SystemMetaObject.forObject(target);
        Object value = null;
        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);
        value = forObject.getValue("parameterHandler.parameterObject");
        System.out.println("最里面包装的真是代理对象用到的参数是:"+value);

        forObject.setValue("parameterHandler.parameterObject",5);

        Object proceed = invocation.proceed();
        return proceed;
    }

    @Override
    public Object plugin(Object target) {
        System.out.println("MySecondPlugin....plugin代理:"+target);
        Object wrap = Plugin.wrap(target, this);
        return wrap;
    }

    @Override
    public void setProperties(Properties properties) {
        System.out.println("MySecondPlugin...setProperties:" +properties);

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值