本文主要分析MyBatis的插件机制,实际就是Java动态代理实现的责任链模式实现。
根据官方文档。Mybatis只允许拦截以下方法,这个决定写拦截器注解签名参数。
代码如下 | 复制代码 |
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) ParameterHandler (getParameterObject, setParameters) ResultSetHandler (handleResultSets, handleOutputParameters) StatementHandler (prepare, parameterize, batch, update, query) |
拦截处理的源码如下,其中interceptorChain.pluginAll(..)即为织入自定义拦截器:
代码如下 | 复制代码 |
/* org.apache.ibatis.session.Configuration类中方法 */ public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { public Executor newExecutor(Transaction transaction, ExecutorType executorType) { |
实现一个自定义拦截器只需实现Interceptor接口即可,大致代码如下:
代码如下 | 复制代码 |
/* 注解表明要拦截哪个接口的方法及其参数 */ public Object intercept(Invocation invocation) throws Throwable{ /*生成成对目标target的代理,而@Intercepts的注解是在Plugin.wrap中用到*/ /*用于设置自定义的拦截器配置参数*/ |
其中,拦截调用的代码均在Plugin.wrap中:
代码如下 | 复制代码 |
/* org.apache.ibatis.plugin.Plugin类 */ /* 省略代码... */ public static Object wrap(Object target, Interceptor interceptor) { /* 拦截目标类的所有方法的执行都会变为在此执行 */ /* 省略代码... */ } |
可以看到MyBatis的拦截器设计核心代码还是比较简单的,但是足够灵活。实际使用时注意,不做无意义的代理(Plugin.wrap)。