九.插件
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);
}
}