MyBatis-08 插件开发

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中插件开发的具体测试代码下载地址:https://download.csdn.net/download/bingbeichen/10540317


1. 插件原理

在四大对象创建时,所创建的对象均需经过interceptorChain.pluginAll();方法对其进行包装,而不是直接返回的。

包装过程即获取到所有的Interceptor(拦截器,其是插件需要实现的接口),并调用interceptor.plugin(target);方法返回target经过包装后的对象。

插件机制即是使用插件为目标对象创建一个代理对象,代理对象可以拦截到目标对象,控制目标对象各个方法的执行,类似于Spring的AOP编程。


2. 插件开发步骤

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

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

    /**
     * 拦截目标方法执行
     * 
     * 实现:显示查询1号员工信息,实则查询4号员工信息
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("myFirstPlugin.intercept() : " + invocation.getMethod());

        Object target = invocation.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(target);
        Object value = metaObject.getValue("parameterHandler.parameterObject");
        System.out.println("SQL语句传入的参数为:" + value);
        metaObject.setValue("parameterHandler.parameterObject", 5);

        // 执行目标方法
        Object proceed = invocation.proceed();
        return proceed;
    }

    /**
     * 生成动态代理对象,可以使用MyBatis提供的Plugin类的wrap方法
     */
    @Override
    public Object plugin(Object target) {
        System.out.println("myFirstPlugin.plugin() : 待包装的对象为" + target);
        // 获取包装后的动态代理对象
        Object wrap = Plugin.wrap(target, this);
        return wrap;
    }

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

}

第二步,在全局配置文件中注册自定义插件。

<plugins>
        <plugin interceptor="com.qiaobc.mybatis.plugin.MyFirstPlugin"></plugin>
</plugins>

3. 多插件运行流程

按照插件配置顺序调用插件plugin()方法,生成被拦截对象的动态代理对象。

多个插件依次生成目标对象的代理对象,层层包裹,先声明的先包裹,形成代理链。目标方法执行时依次从外到内执行插件的intercept()方法。

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

/**
 * 从代理链中分离真实被代理对象
 */
//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);

猜你喜欢

转载自blog.csdn.net/bingbeichen/article/details/81036507