插件原理
* 在四大对象创建的时候
* 1、每个创建出来的对象不是直接返回的,而是
* interceptorChain.pluginAll( parameterHandler )
*
* 2、获取到所有的interceptor(基于拦截器原理)(插件需要实现的接口)
* 调用所有的Interceptor.pluginAll(target);返回target包装后的对象
* 3、插件机制,我们可以使用插件为目标对象创建一个代理对象:AOP(面向切面的方式)
* 我们的插件可以为四大对象创建出代理对象
* 代理对象就可以拦截到四大对象的每一个执行方法
public Object pluginAll(Object target){ for (Interceptor interceptor:interceptors) { target = interceptor.plugin(target); } return target; }
插件编写:
1、编写Interceptor的实现类
2、使用@Intercepts注解完成插件签名
/** * 完成了插件签名:告诉mybatis当前插件用来拦截哪个对象的哪个方法 */ @Intercepts({ @Signature(type = StatementHandler.class,method = "parameterize",args = java.sql.Statement.class) }) public class MyFirstPlugin implements Interceptor { /** * intercept:拦截 * 拦截目标对象的方法的执行 * @param invocation * @return * @throws Throwable */ @Override public Object intercept(Invocation invocation) throws Throwable { System.out.println("MyFirstPlugin....interceptor:"+invocation.getMethod()); //执行目标方法 Object proceed = invocation.proceed(); //返回执行后的返回值 return proceed; } /** * plugin:包装目标对象——包装:为目标对象创建一个代理类 * @param target * @return */ @Override public Object plugin(Object target) { System.out.println("MyFirstPlugin....plugin:mybatis将要包装的对象"+target); //我们可以借助Plugin的wrap方法来使用当前的intercept包装我们目标对象 Object wrap = Plugin.wrap(target, this); //返回为当前target创建好的动态代理 return wrap; } /** * setProperties:将插件注册时的property属性设置进来 * @param properties */ @Override public void setProperties(Properties properties) { System.out.println("插件配置的信息"+properties); } }
3、将写好的插件注册到全局配置文件中
<!--
注册插件
interceptor:插件的全类名
-->
<plugins>
<plugin interceptor="dao.MyFirstPlugin">
<!--一下属性会被插件的属性包装-->
<property name="username" value="root"/>
<property name="password" value="123456"/>
</plugin>
</plugins>
运行结果:
多个插件运行原理
@Intercepts( { @Signature(type = StatementHandler.class,method = "parameterize",args = java.sql.Statement.class) } ) public class MySecondPlugin implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { System.out.println("MySecondPlugin.....interceptor"+invocation.getMethod()); Object proceed = invocation.proceed(); return proceed; } @Override public Object plugin(Object o) { System.out.println("MySecondPlugin.....plugin"+o); return Plugin.wrap(o,this); } @Override public void setProperties(Properties properties) { } }
<plugins> <plugin interceptor="dao.MyFirstPlugin"> <!--一下属性会被插件的属性包装--> <property name="username" value="root"/> <property name="password" value="123456"/> </plugin> <plugin interceptor="dao.MySecondPlugin"></plugin> </plugins>
多个插件就会产生多层代理
创建动态代理的时候是按照插件配置顺序创建层层动态代理对象,执行目标方法的时候是按照逆序来的