1.mybatis拦截器的使用
1.1拦截器的实现 import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.plugin.*; import java.sql.Connection; import java.util.Properties; @Intercepts({@Signature(type= StatementHandler.class,method="prepare",args={Connection.class,Integer.class})}) public class PaginationInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { //实现插件逻辑 return invocation.proceed(); } @Override public Object plugin(Object target) { //固定步骤,对目标对象进行代理,代理后将目标对象,目标方法,方法参数封装成 Invocation调用 intercept方法 return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } }
1.2将拦截器注入mybatis
可以获取Configuration直接Add单此方法在需要配置文件的时候不可取,他不会调用setProperties
可以通过配置文件加入
2.mybatis拦截器实现
1.对于使用者来说需要手动通过Plugin.wrap对拦截器进行代理,将代理后的对方返回mybatis中。该类实现的JDK动态代理接口InvocationHandler,拦截目标对象目标方法。调用拦截器的intercept(Invocation invocation),将目标对象,目标方法,方法参数封装成执行器Invocation作为参数传入。对用户可见的就是执行器,用户只需要获取拦截器中的原始类,结合metaObject操作原始类里面的参数等相关步骤后,执行执行器里面的方法,有点类似于Spring的环绕通知;Plugin就相当于一个工具类帮助用户完成:解析拦截器的注解完成需要拦截的方法拦截;将目标对象,参数,方法封装成执行类,传给intercept方法供用户使用;看似mybatis提供的工具类帮助用户完成代理逻辑,实则用户操作只是一个可有可无的中间步骤后面是mybatis自己的步骤
Plugin代理步骤如下
1.方法调用入口
创建Sqlsession时对执行器做代理
获取ParameterHandler参数
获ResultSetHandler时
获取StatementHandler时
2.方法代理入口,调用拦截器的plugin方法完成目标对象的代理
3.通过Plugin对目标对象进行代理
4.Plugin.wrap方法,用户需要手动通过Plugin.wrap方法对目标对象进行代理(个人感觉可以选择将代理步骤封装在框架内部,拦截器接口只提供intercept 和setProperties方法,这样用户就不需要参与对象的代理过程;当然用户也可以不通过Plugin和使用mybatis提供的注解@Intercepts实行拦截器逻辑直接在拦截器类实现相应代理逻辑)
在该方法中解析注解 @Intercepts 解析出拦截的对象,拦截的方法,后对目标对象进行代理。代理实现方法为Plugin插件类的
思考
1.为什么mybatis使用JDK动态代理不使用Cglib
2.为什么不将代理步骤plugin纳入框架内部而是用户自己做手动通过Plugin.wrap封装后调用intercept方法