一、插件原理
1、MyBatis在四大对象的创建过程中,都会有插件进行介入。插件可以利用动态代理机制一层层的包装目标对象,而实现在目标对象执行目标方法之前进行拦截的效果。
2、MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用。
3、默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
•Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
•ParameterHandler(getParameterObject, setParameters)
•ResultSetHandler(handleResultSets, handleOutputParameters)
•StatementHandler(prepare, parameterize, batch, update, query)
/** * 插件原理 * 在四大对象创建的时候 * 1、每个创建出来的对象不是直接返回的,而是 * xxx = interceptorChain.pluginAll(parameterHandler); 具体方法如下:其实就是遍历调用了每个插件的plugin(target)方法, 如果插件的方法签名和目标对象一致,就返回目标对象的代理对象,否则就返回目标对象 public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { target = interceptor.plugin(target); } return target; } * 2、获取到所有的Interceptor(拦截器)(插件需要实现的接口); * 调用interceptor.plugin(target);返回target包装后的对象 * 3、插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP(面向切面) * 我们的插件可以为四大对象创建出代理对象; * 代理对象就可以拦截到四大对象的每一个执行; * */
接口方法:
•Intercept:拦截目标方法执行
•plugin:生成动态代理对象,可以使用MyBatis提供的Plugin类的wrap方法
•setProperties:注入插件配置时设置的属性
二、插件编写过程
1、编写Interceptor的实现类
package com.mybatis.plugin; import java.util.Properties; import org.apache.ibatis.executor.parameter.ParameterHandler; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.SystemMetaObject; /** * 完成插件签名: * 告诉MyBatis当前插件用来拦截哪个对象的哪个方法 */ @Intercepts( { @Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class) }) public class MyFirstPlugin implements Interceptor{ /** * intercept:拦截: * 拦截目标对象的目标方法的执行; */ @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; } /** * plugin: * 包装目标对象的:包装:为目标对象创建一个代理对象 */ @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; } /** * setProperties: * 将插件注册时 的property属性设置进来 */ @Override public void setProperties(Properties properties) { // TODO Auto-generated method stub System.out.println("插件配置的信息:"+properties); } }
2、使用@Intercepts注解完成插件签名
已经在前面的MyFirstPlugin.java
添加了,注解签名。
@Intercepts( { @Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class) })
3、将写好的插件注册到全局配置文件中
在mybatis-config.xml中,添加插件配置项:
<!--plugins:注册插件 --> <plugins> <plugin interceptor="com.atguigu.mybatis.dao.MyFirstPlugin"> <property name="username" value="root"/> <property name="password" value="123456"/> </plugin> <plugin interceptor="com.atguigu.mybatis.dao.MySecondPlugin"></plugin> </plugins>
三、多插件加载顺序
会根据mybatis的配置的插件顺序依次加载。
一个目标对象如果有多个插件,会在目标的代理对象上继续创建代理。