1.介绍 :
我自己理解中的mybatis拦截器,和普通拦截器一样,在执行一段程序之前对其做一些特殊处理,网上一般都是用其做分页处理、日志记录...,实现原理就是在预处理前对其进行一些处理
2.简单说明:
mybatis提供了一个Interceptor接口,方便扩展所需的操作
Object intercept(Invocation invocation)
Object plugin(Object target)
void setProperties(Properties properties)
我们所需实现的便是以上的三个方法,先对每个方法有个大致了解
2.1 先说setProperties方法,我们在mybatis.xml配置文件中有一个plugins标签,其中的一个plugin标签对应着一个Interceptor实现类。在plugin标签下,含有property标签用于存放一些我们可修改的配置信息
举个例子,mysql、sqlServer、oracle他们sql分页的语句都有一定的区别,所以为了区分,我们便可以使用此配置(这个不是重点,其他两个才是)
2.2 plugin决定我们是否要拦截,拦截条件是什么,返回的是一个什么样的对象
2.3 intercept方法就是拦截期间我们所做的操作
3.实现过程 :
3.1 首先封装一个分页数据对象,最少3个参数(页码、每页记录数、起始记录数(算出来的))
3.2 创建一个实现Interceptor接口的对象,添加注解@Intercepts和@Signature,这里有两个重点
3.2.1 我们如何使用这两个注解?
@Signature注解信息更加具体,相当于集合的一个元素,@Intercepts就相当于集合了
@Signature包含三个参数:(这样就具体的定位了)
method : 表示拦截的方法
type :表示拦截的类,Executor、StatementHandler、ParameterHandler和ResultSetHandler这四个接口的实现类
args:表示方法参数
例如:@Intercepts( {@Signature(method = "query", type = Executor.class, args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }),
@Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class}) })
3.2.2 如何读取注解信息?
上文说到plugin指定在什么地方拦截,那么此方法就需要识别这两个注解。当然提供两个注解的是Mybatis,那么mybatis肯定也有解析这两个注解的类,
Plugin里面有一个静态方法wrap(Object target,Interceptor interceptor)。所以一般plugin里面只要写Plugin.wrap(target,this);就可以了
3.3 忘了说一点,我们setProperties是最先执行的,所以我们需要预先定义变量来保存配置参数
3.4 已经拦截了,那么我们先获取当前拦截类,读取拦截类信息,再进行下一步操作(具体案例来分析)
利用拦截器实现Mybatis分页的原理:
* 要利用JDBC对数据库进行操作就必须要有一个对应的Statement对象,Mybatis在执行Sql语句前就会产生一个包含Sql语句的Statement对象,而且对应的Sql语句
* 是在Statement之前产生的,所以我们就可以在它生成Statement之前对用来生成Statement的Sql语句下手。在Mybatis中Statement语句是通过RoutingStatementHandler对象的
* prepare方法生成的。所以利用拦截器实现Mybatis分页的一个思路就是拦截StatementHandler接口的prepare方法,然后在拦截器方法中把Sql语句改成对应的分页查询Sql语句,之后再调用
* StatementHandler对象的prepare方法,即调用invocation.proceed()。
//对于StatementHandler其实只有两个实现类,一个是RoutingStatementHandler,另一个是抽象类BaseStatementHandler,
//BaseStatementHandler有三个子类,分别是SimpleStatementHandler,PreparedStatementHandler和CallableStatementHandler,
//SimpleStatementHandler是用于处理Statement的,PreparedStatementHandler是处理PreparedStatement的,而CallableStatementHandler是
//处理CallableStatement的。Mybatis在进行Sql语句处理的时候都是建立的RoutingStatementHandler,而在RoutingStatementHandler里面拥有一个
//StatementHandler类型的delegate属性,RoutingStatementHandler会依据Statement的不同建立对应的BaseStatementHandler,即SimpleStatementHandler、
//PreparedStatementHandler或CallableStatementHandler,在RoutingStatementHandler里面所有StatementHandler接口方法的实现都是调用的delegate对应的方法。
//我们在PageInterceptor类上已经用@Signature标记了该Interceptor只拦截StatementHandler接口的prepare方法,又因为Mybatis只有在建立RoutingStatementHandler的时候
//是通过Interceptor的plugin方法进行包裹的,所以我们这里拦截到的目标对象肯定是RoutingStatementHandler对象。
上述内容都来自于 http://elim.iteye.com/blog/1851081?page=2#comments (详细请观看这个博客)
3.4.1 RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();//用来获取当前拦截类
拦截之后我们需要知道接下来该做什么,这又是另一个话题了,这里说个题外话,我觉得MySql可能并不太需要这部分的处理,limit函数友好的帮我们处理了这一类问题
@——@以上信息纯属胡说八道