赞
踩
MyBatis所述的插件功能,其实就是一个拦截器
功能。
1、在四大对象创建的时候,每个创建出来的对象不是直接返回的,而是通过interceptorChain.pluginAll(parameterHandler)
返回的。
2、pluginAll获取到所有的Interceptor(拦截器)(插件需要实现的接口),调用Interceptor.pluginAll(target)
,返回target被包装后的对象
。
3、插件机制:我们可以使用插件为目标对象创建一个代理对象
:AOP(面向切面)
我们的插件可以为四大对象
创建出代理对象
,代理对象
就可以拦截
四大对象的每一个执行(方法)
。
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
实现自定义插件,需要实现org.apache.ibatis.plugin.Interceptor
接口。
/**
* 完成插件签名:
* 告诉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 {
System.out.println("MyFirstPlugin... intercept before:" + invocation.getMethod());
// 执行目标方法
Object proceed = invocation.proceed();
System.out.println("MyFirstPlugin... intercept after:" + invocation.getMethod());
// 返回执行后的返回值
return proceed;
}
/**
* plugin:
* 包装目标对象:包装,为目标对象创建一个代理对象
*/
@Override
public Object plugin(Object target) {
System.out.println("MyFirstPlugin... plugin:mybatis将要包装的对象" + target);
// 我们可以借助Plugin的wrap方法来使用挡圈Interceptor包装我们目标对象
Object wrap = Plugin.wrap(target, this);
// 返回为当前target创建的动态代理
return wrap;
}
/**
* setProperties:
* 将插件注册时的property属性设置进来
*
*/
@Override
public void setProperties(Properties properties) {
System.out.println("插件配置的信息:" + properties);
}
}
注释,接口里面共有三个方法。
(1)intercept方法:
拦截目标方法,在其前后都可以进行业务逻辑,使用invocation.proceed();
执行方法。
(2)plugin方法:
包装target目标为代理对象,可以自己写创建代理对象的逻辑,也可以使用MyBatis提供的快捷方式去创建代理对象Object wrap = Plugin.wrap(target, this);
,第二个this就是当前的拦截器。
(3)setProperties方法:
在全局配置文件注册插件时,可以设置一些property属性,通过该方法的入参获取。
如以下的全局配置文件,设置了两个property,可以通过入参获取到:
<!-- plugins:注册插件 -->
<plugins>
<plugin interceptor="com.shen.mybaties.dao.MyFirstPlugin">
<property name="username" value="root" />
<property name="password" value="123456" />
</plugin>
</plugins>
光实现接口还不行,因为没有指定拦截哪一个类,拦截哪一个方法
。
需要在插件类上加一个@Intercepts
,它有三个属性
(1)type:类类型,就是some.class
(2)method:需要拦截的方法名
(3)args:由于可能存在方法重载,故需要通过参数类型来确定拦截的方法,同样是类类型(.class
)
全局配置文件加入如下配置:
<configuration>
<!-- plugins:注册插件 -->
<plugins>
<plugin interceptor="com.shen.mybaties.dao.MyFirstPlugin">
<property name="username" value="root" />
<property name="password" value="123456" />
</plugin>
</plugins>
</configuration>
在plugin方法中,我们使用MyBatis提供的快捷方法Plugin.wrap(target, this);
,可以快速得到一个代理对象。
plugin产生的代理对象,其中target
才是真正的对象。
模仿First插件。
多个插件包装对象时,每次都进行一次包装,第二次传入的target为第一次包装的代理对象,造成一层包一层的情况。
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
创建动态代理的时候,是按照插件配置顺序创建层层代理的对象。
执行目标方法的时候,按照逆向顺序执行。
插件开发,主要需要知道被代理对象有哪些属性
,如修改查询参数。
@Override
public Object intercept(Invocation invocation) throws Throwable {
MetaObject metaObject = SystemMetaObject.forObject(invocation.getTarget());
Object value = metaObject.getValue("parameterHandler.parameterObject");
metaObject.setValue("parameterHandler.parameterObject",2);
// 执行目标方法
Object proceed = invocation.proceed();
// 返回执行后的返回值
return proceed;
}
这里,需要知道被代理对象,有一个属性为parameterHandler
,属性的属性parameterObject
是控制参数预编译的参数,我们需要修改这个。
使用MyBatis提供的SystemMetaObject
的getValue
和setValue
方法进行修改,达到目的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。