Mybatis插件

来源:互联网 发布:oracle删除重复数据 编辑:程序博客网 时间:2024/05/21 07:54

在Mybatis的Configuration对象的创建方法里可以看到Mybatis用责任链去封装它们。我们便可以在四大对象调度的时候插入我们的代码,这就是Mybatis的插件技术。
Mybatis插件必须实现Interceptor接口,3个方法:intercept方法将直接覆盖锁拦截对象的原有的方法,plugin方法给被拦截对象生成一个代理对象,setsetProperties在plugin元素中配置所需参数在插件初始化的时候被调用一次然后把插件对象存入到配置中以便后面再取出。
插件初始化是在Mybatis初始化的时候完成。Mybatis解析配置文件上下文初始化的过程中就开始读入插件节点和我们配置的参数,同时用反射生成对应的插件实例,然后调用插件中的setProperties方法设置配置的参数,然后将插件实例保存到配置对象中,以便读取和使用。所以插件实例是一开始就被初始化的。
插件使用的是责任链模式,从第一个对象(四大对象中的一个)开始,将对象传递给plugin方法,plugin中wrap方法返回一个代理。如果存在第二个插件,那么就拿到第一个代理对象传递给plugin再返回第一个代理对象的代理,有多少给拦截器就生成多少给代理对象,这样每个插件都可以拦截到真实的对象。
创建一个Invocation对象,其构造方法的参数包括被代理的对象、方法及其参数Invocation对象进行初始化,它有一个proceed方法就是调度被代理对象的真实方法。假设有n个插件,第一个传递的参数是四大对象本身,然后调用一次wrap方法产生一个代理对象,这里的反射就是反射四大对象的真实方法。如果有第二个插件,将第一个插件的代理对象传递给wrap生成第二个代理对象,这里的反射就是第一个代理对象的invoke方法,依此类推直到最后一个代理对象。每一个对象都调用proceed方法,最后四大对象本身的方法也会被调用,从第一个代理对象的invoke方法运行到最后一个代理对象的invoke方法,直到四大对象的真实方法。

初始化时,我们一个个加载插件实例,并用setProperties方法进行初始化。用Plugin.wrap方法生成代理对象,再一层层使用Invocation对象的proceed方法来推动代理对象运行。所以多个插件的环境下Mybatis总是从最后一个代理对象运行到第一个代理对象,最后是真实被拦截的对象的方法被运行。

编写插件实例:

StatementHandler statementHandler = (StatementHandler) invocation.getTarget();//包装对象MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);//进行绑定//分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过循环分离出最原始的目标类)while (metaStatementHandler.hasGetter("h")) {    Object object = metaStatementHandler.getValue("h");    metaStatementHandler = SystemMetaObject.forObject(object); }//BoundSql对象处理sqlString sql = (String)metaStatementHandler.getValue("delagate.boundSql.sql");//判断sql是否是select语句,如果不是就出错了//如果是,修改它,最多返回1000行if (sql != null $$sql.toLowerCase().trim().indexOf("select") == 0) {    //通过SQl重写来实现,起一个奇怪的别名,避免与表名重复    sql = "select * from (" + sql + ") $_$limit_$table_limit 1000";    metaStatementHandler.setValue("delegate.boundSql.sql", sql);}

插件开发拦截对象
·Executor是执行SQL的全过程,包括组装参数,组装结果集返回和执行SQL过程,都可以拦截,较为广泛一般用的不多
·StatementHandler是执行SQL的过程,是常用的拦截对象
·ParameterHandler拦截执行SQL的参数组装,可以重写组装参数规则
·ResultSetHandler用于拦截执行结果的组装,可以重写组装结果的规则

原创粉丝点击