目录
在新项目中有个需求,需要记录下增删改的SQL并落表。一般考虑到的是需要利用Spring的AOP,抽取日志记录的功能,在持久层操作的时候进行统一增强。项目用到的持久层框架是MyBatis,那么直接想到的就是利用MyBatis的插件机制对执行的SQL进行记录。那么具体如何实现呢?原理又是什么?读了这篇文章的小伙伴就可以搞清楚啦。
工程源码在最后~
一、MyBatis插件介绍
MyBatis大家都比较熟悉,实际使用也非常广泛,其内部提供了插件扩展机制来拦截SQL的执行。
其执行原理如下图所示:
SQL执行依赖于sqlSession,是MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能,sqlSession又依赖Executor执行器,执行器负责SQL语句的生成和查询缓存的维护,既然是封装了JDBC,SQL构建也是必不可少的,MyBatis封装了StatementHandler,对于参数处理和结果集处理用到了ParameterHandler和ResultSetHandler这两个处理器。对于这四大组件的说明如下:
组件 | 说明 |
Executor | MyBatis执行器,是MyBatis调度的核心,负责SQL语句的生成和查询缓存的维护 |
StatementHandler | 封装了JDBC Statement操作,负责对JDBC statement的操作,如设置参 数、将Statement结果集转换成List集合。 |
ParameterHandler | 负责对用户传递的参数转换成JDBC Statement所需要的参数 |
ResultSetHandler | 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合 |
当然MyBatis的核心组件不只有这些,还包括TypeHandler(java和mysql类型转换)等,但是我们的插件主要拦截的是这四大组件。对MyBatis来说插件就是拦截器,用来增强核心对象的功能,增强功能本质上是借助于底层的动态代理实现的,换句话说,MyBatis中的四大对象都是代理对象。
MyBatis所允许拦截的方法如下:
- 执行器Executor (update、query、commit、rollback等方法);
- SQL语法构建器StatementHandler (prepare、parameterize、batch、updates query等方 法);
- 参数处理器ParameterHandler (getParameterObject、setParameters方法);
- 结果集处理器ResultSetHandler (handleResultSets、handleOutputParameters等方法);
二、MyBatis插件原理
在四大对象创建的时候
- 1、每个创建出来的对象不是直接返回的,而是interceptorChain.pluginAll(parameterHandler);
- 2、获取到所有的Interceptor (拦截器)(插件需要实现的接口);调用 interceptor.plugin(target);返回target包装后的对象
- 3、插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP (面向切面)我们的插件可以为四大对象创建出代理对象,代理对象就可以拦截到四大对象的每一个方法
以ParameterHandler为例,我们看下源码分析一下:
public ParameterHandler newParameterHandler(MappedStatement map