mybatis的插件原理可参考博文,http://blog.csdn.net/hupanfeng/article/details/9247379,本文可作为补充。
1、mybatis的自定义插件,需要实现Interceptor接口,里面有三个接口:
Object intercept(Invocation var1) throws Throwable;
Object plugin(Object var1);
void setProperties(Properties var1);
调用顺序分别是:setProperties(xxx) => plugin(xx), => intercept(xxx);第一个是设置参数,第二个是生成动态代理(为考虑性能,一般会判断是否当前信息是否是当前插件需要拦截的动作),第三个是执行(额,也就是自定义插件的具体内容需要写在这里)。
2、InterceptorChain里保存了所有的拦截器,他有一个pluginAll方法用来创建已注册的插件的动态代理,
该方法的其中一条调用路径(执行一条SQL时,即使是执行一条SQL这样简单的任务,pluginAll也可能会被调用很多次)如下图所示:
而InterceptorChain里注册的插件interceptors是在解析XML配置时注入的,
3、Object plugin(Object var1);
假设原始对象的类型是T,被拦截的方法是m.
该方法返回插件的代理对象(是JVM临时生成的一个继承T的类(如,$Proxy35),同时传入一个InvocationHandler对象(ProxyWrapper)或者原始对象,该类有三个成员,target、interceptor和signatureMap。
target是下一层插件的代理对象或原始对象(你看,这就构成了代理链);
interceptor是当前层次的插件;
signatureMap保存了哪些类(原始对象对应的类)的哪些方法被拦截
4、Object intercept(Invocation var1);
参数传入的是代理链接上的下一个插件的相关参数,Invocation同样包含三个成员,target、method和args。
target是下一级插件的代理对象或原始对象,method被拦截的方法,args对应参数。
末尾有一句
如果target是插件的话,触发插件的执行(即经历代理对象的invoke(xx)=> ProxyWrapper的invoke(xxx)=>插件的intercept(xxx)),如此循环;
如果target是目标类的话,那么调用被拦截的方法。
5、最外一层的代理对象的invoke方法何时被调用呢?
最外层的代理对象,因为继承了T,所以可以显式调用方法m,从而转到代理对象的invoke方法,进而转到ProxyWrapper的invoke方法里.
例如:
当handler是个代理对象时,handler.prepare(xxx)的调用会转成代理对象(如类名为”$Proxy35”的对象)的invoke方法的调用,再转到ProxyWrapper的invoke方法里,进而转到插件的intercept(xx)里面,你看进入4的循环了。
6、ProxyWrapper的invoke方法
这里,如果被调用的方法是被拦截的方法,那么调用插件的intercept(xxx)方法,并结束;否则呢,调用原始对象的被拦截方法。