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 函数友好的帮我们处理了这一类问题
@--@以上信息纯属胡说八道
来源: http://www.bubuko.com/infodetail-2737625.html