版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38409944/article/details/82494624
Mybatis插件原理和执行流程
对四大对象和插件有了一定了解后,这里我就开始简单实现一个自定义插件,来拦截四大对象,实现拦截器功能。
步骤:
1. 编写Interceptor的实现类
2. 使用@Intercepts注解完成插件签名 说明插件的拦截四大对象之一的哪一个对象的哪一个方法
3. 将写好的插件注册到全局配置文件中
编写Interceptor的实现类(dao层)以及注解声明
注解参数:
type:拦截对象(四大对象之一)
method:拦截对象的方法
args:当前方法的参数列表
编写Interceptor的实现类:
@Intercepts({
@Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class)
})
public class MyfirstPlugin implements Interceptor {
/**
* 拦截目标对象的目标方法的执行;
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
// TODO Auto-generated method stub
System.out.println("要拦截的方法"+invocation+invocation.getMethod());
Object prObject = invocation.proceed();
return prObject;
}
/**
* 包装目标对象的:包装:为目标对象创建一个代理对象
*/
@Override
public Object plugin(Object target) {
// TODO Auto-generated method stub
System.out.println("包装的对象"+target.toString());
Object wrap = Plugin.wrap(target, this);
return wrap;
}
/**
* setProperties:
* 将插件注册时 的property属性设置进来
*/
@Override
public void setProperties(Properties properties) {
// TODO Auto-generated method stub
System.out.println(properties);
}
}
全局配置文件:
<plugins>
<plugin interceptor="dao.MyfirstPlugin">
<property name="root" value="jjc"/>
<property name="pwdword" value="123456"/>
</plugin>
</plugins>
注意:
如果是 两个不同的插件对同一个对象的同一个方法进行拦截的时候
第一个插件的plugin方法的参数是未包装对象
第二个插件的plugin方法的参数是第一个插件包装后的对象
举一个栗子:当你查询id为2的内容 结果显示id为4的内容
查看id内容存放位置:
包装的对象org.apache.ibatis.executor.statement.RoutingStatementHandler@7c541c15
根据以上的内容知道创建的StatementHandler接口实现类是RoutingStatementHandler 是中间类
然后 找到这个类 :默认是PREPARED
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
再进入PreparedStatementHandler类:
@Override
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
parameterHandler是BaseStatementHandler的属性
相当于parameterHandler是PreparedStatementHandler的属性
这个接口实现类是:DefaultParameterHandler
DefaultParameterHandler类中属性:
Object parameterObject封装的就是参数值
MappedStatement mappedStatement封装当前对象的增删改查详细信息的
BoundSql boundSql封装sql的详细信息的
编写截目标对象的目标方法的执行:
@Override
public Object intercept(Invocation invocation) throws Throwable {
// TODO Auto-generated method stub
System.out.println("要拦截的方法"+invocation+invocation.getMethod());
//得到当前对象
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("当前参数值:"+value);
//修改完sql语句要用的参数
metaobject.setValue("parameterHandler.parameterObject", 4);
//执行原来的方法
Object prObject = invocation.proceed();
return prObject;
}