MyBatis9-插件

九.插件

9.1 插件原理

在四大对象创建的时候
1.每个对象创建出来的对象不是直接返回的,而是调用了interceptorChain.luginAll(parameterHandler)
2.获取到所有的Interceptor(拦截器)(插件需要实现的接口)
调用interceptor.plugin(target);返回target包装后的对象
3.插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP(面向切面)
我们的插件可以为四大对象创建出代理对象;代理对象就可以拦截到四大对象的每一个执行

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

9.2 插件编写

9.2.1 编写Interceptor的实现类
9.2.2 使用@Intercepts注解完成插件签名
/*
    用这个标签告诉MyBatis需要拦截那个对象的那个方法,拦截到以后跳转到intercept方法中
*/
@Intercepts(
        {
               @Signature(type = StatementHandler.class,method = "parameterize",args = Statement.class)
        }
)
public class MyFirstPlugin implements Interceptor{

    /*
        intercept:拦截
            拦截目标对象的目标方法的执行;
    */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
      System.out.println("MyFirstPlugin...intercept:"+invocation.getMethod());
        //执行目标方法
        Object proceed=invocation.proceed();
        //返回执行以后的返回值
        return proceed;
    }

    /*
        包装目标对象:为目标对象创建一个代理对象
    */
    @Override
    public Object plugin(Object o) {
        System.out.println("MyFirstPlugin...intercept:MyBatis将要包装的对象:"+o);
        /*代理对象的生成,我们可以借助Plugin的wrap*/
        Object wrap=Plugin.wrap(o,this);
        //返回创建的代理对象
        return wrap;
    }

    /*
     将插件注册时的property属性设置进来
    */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件配置的信息: "+properties);
    }
}
9.2.3 将写好的插件注册到全局配置文件中
<plugins>
    <plugin interceptor="com.itlc.mybatis.dao.MyFirstPlugin">
        <!--参数设置-->
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </plugin>
</plugins>

9.3 多个插件

写多个插件时,配置也需要配置多次
创建动态代理的时候,是按照插件配置顺序创建层层代理对象。
执行目标方法的之后,按照逆向顺序执行

9.4 自定义插件

//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)

使用实例

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

    /*
        intercept:拦截
            拦截目标对象的目标方法的执行;
    */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //执行方法,将查询1号变成查询7号
        Object target=invocation.getTarget();
        System.out.println("当前拦截到的对象"+target);
        //拿到StatementHandle==>ParameterHandler==>parameterObject
        //拿到target的原数据
        MetaObject metaObject = SystemMetaObject.forObject(target);
        Object value=metaObject.getValue("parameterHandler.parameterObject");
        System.out.println("sql语句用的参数是:"+value);
        //修改参数的值
        metaObject.setValue("parameterHandler.parameterObject",7);
        value=metaObject.getValue("parameterHandler.parameterObject");
        System.out.println("sql语句用的新参数是:"+value);
        //执行目标方法
        Object proceed=invocation.proceed();
        //返回执行以后的返回值
        return proceed;
    }

    /*
        包装目标对象:为目标对象创建一个代理对象
    */
    @Override
    public Object plugin(Object o) {
        System.out.println("MyFirstPlugin...intercept:MyBatis将要包装的对象:"+o);
        /*代理对象的生成,我们可以借助Plugin的wrap*/
        Object wrap=Plugin.wrap(o,this);
        //返回创建的代理对象
        return wrap;
    }

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

猜你喜欢

转载自blog.csdn.net/maniacxx/article/details/80390024