mybatis支持拦截器,实现的原理就是利用JDK的动态代理。先前利用拦截器实现了分页功能,如今又利用拦截器实现日志记录的功能,感觉拦截器还是不错的,只是相对于spring3 mvc的拦截器感觉有些逊色。接下来,我着重分析一些拦截的使用。
【基本思路】拦截器在哪里拦截?什么情况下才会拦截代理?怎么代理呢?只要搞清楚这些,基本的拦截器功能也就了如指掌啦。
拦截器在哪里呢?mybatis到底提供几处可以拦截呢?请看下图,通过分析源码可知基本查询流程如下:
【简洁的流程】 首先mybatis初始化加载的时候,利用
MapperProxy代理
自己的Mapper接口类,
生成一个代理处理类,代理处理的逻辑都在
invoke方法里,首先获取到目标类的接口
declaringInterface,然后生成
MapperMethod,(其中
sqlSession是
SqlSessionTemplate,是spring连接mybatis的模板类,是由spring负责生成的),生成了
MapperMethod,直接调用
MapperMethod可执行的方法
execute就能获取执行结果,整个流程非常简洁,非常和spring3 mvc的servlet实现类似,也就是说,
MapperMethod就是一个命令,执行命令获取执行结果,也就是标准的命令模式。整个流程代码如下:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
final Class<?> declaringInterface = findDeclaringInterface(proxy, method);
final MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, sqlSession);
final Object result = mapperMethod.execute(args);
if (result == null && method.getReturnType().isPrimitive()
&& !method.getReturnType().equals(Void.TYPE)) {
throw new BindingException(
"Mapper method '" + method.getName() + "' (" + method.getDeclaringClass()
+ ") attempted to return null from a method with a primitive return type ("
+ method.getReturnType() + ").");
}
return result;
}
【分步分析】
查看excute方法可知,就是根据不同的sql类型,交给sqlSession,也就是SqlSessionTemplate类的对象,主要是完成获取执行参数
param
和
commandName,执行具体的操作,例如,
result =
sqlSession
.
selectList
(
commandName
, param);
。
其中sql类型的获取可参考初始化的时候加载的setupCommandType(),初始化的时候还包括获取map的sqlID等
-
SqlSessionTemplate和
SqlSessionInterceptor
利用eclipse的f4一下,可知
SqlSessionTemplate的实际执行是交给它的代理类完成的。查看
SqlSessionTemplate构造函数可知,是由
SqlSessionInterceptor动态代理的,那么所有的处理逻辑都是在
invoke方法里,从中可知,就是获取SqlSession,执行操作。其中
SqlSessionUtils
.
getSqlSession静态方法调用外部类
SqlSessionTemplate
的
SqlSessionFactory,
ExecutorType,这些都是在mybatis加载
SqlSessionTemplate
构造函数初始化的。
这个就是从
DefaultSqlSessionFactory工厂生成获取的,具体的加载流程就是在
sqlSession
.
selectList静态方法里。
接着上面的查询流程可知,调用的
selectList方法,通过
MapperMethod方法中获取的
commandName,获取到
MappedStatement对象,主要负责的就是sql里xml信息等,具体执行交给
executor,
executor是由
SqlSessionTemplate的
ExecutorType决定的。
executor的获取是
DefaultSqlSessionFactory生成
DefaultSqlSession,加载的方法是在
Configuration里
newExecutor从中可知
cacheEnabled默认为ture,追加缓存实现,具体的实现还是
SimpleExecutor,属于静态代理,
cacheEnabled只是
实现了缓存功能。
executor = (Executor)
interceptorChain
.pluginAll(executor);
表明可追加拦截器。查看代码可知,
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
就是调用拦截Interceptor的方法plugin,我们在plugin方法里一般都需要调用Plugin的静态方法wrap生成Plugin动态代理目标类,由于又是动态代理,实现逻辑都是在invoke方法里,查看可知,调用Interceptor的intercept方法,由Invoction封装目标类,调用方法,调用参数。因此,我们实现自己的拦截器的时候,都可从intercept方法里获取到拦截的对象,方法,参数等。这里其中涉及到两个问题就是拦截器什么情况下才会代理的,怎样代理呢。第一个问题,查看wrap方法可知,就是查看Map里查找是否设定代理啦,以代理对象的class做为key,代理方法的set集合作为value,就能判定是否要代理的。Map里的数据是遍历拦截器的注解Intercepts,实现很简单。怎样打理的,就是调用Interceptor的intercept方法,具体的实现都是在自定义的拦截器方法里。
-
StatementHandler,
ParameterHandler,
ResultSetHandler和
Plugin
由
SimpleExecutor的
doQuery方法是具体的实现,
获取StatementHandler,然后通过StatementHandler获取Statement,其中
StatementHandler的获取又是在Configuration里newStatementHandler,同executor实现的类似,也是有RoutingStatementHandler代理实际的StatementHandler实现,通过StatementType获取具体的StatementHandler类,从默认配置可知,PreparedStatementHandler是实际代理的对象。这里也有
executor = (Executor)
interceptorChain
.pluginAll(executor)可知
同样可添加拦截器。其中构造StatementHandler的时候,查看BaseStatementHandler构造函数可知,ParameterHandler和ResultSetHandler也是有Configuration生成的,同样也可追加拦截器。
由
SimpleExecutor的
doQuery方法调用
prepareStatement
可知,
Statement获取是通过StatementHandler的prepare方法生成的,由于PreparedStatementHandler是具体的实现类,查看可知,instantiateStatement方法里是具体的获取Statement方法,由ConnectionLogger代理类调用PreparedStatementLogger.newInstance生成PreparedStatementLogger。其中ConnectionLogger是DefaultSqlSessionFactory里wrapConnection方法获取的。
【总结】
mybatis的拦截器都是在
Configuration类的
InterceptorChain负责调用位置,Plugin类负责生成代理,调用具体的拦截器实现类
分享到:
相关推荐
下面小编就为大家带来一篇MyBatis拦截器:给参数对象属性赋值的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
通过mybatis拦截器将查询语句、更新语句、删除语句、插入语句中指定表明替换为另一个表名
主要给大家介绍了关于mybatis拦截器实现通用权限字段添加的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用mybatis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
MyBatis拦截器分页与动态修改SQL及其参数值 提取SQL Like 字段
Mybatis拦截器记录数据更新历史记录到MongoDB的源码,另外需要配置拦截器到mybatis配置文件中。
mybatis拦截器的完整实现,test.sql是数据库测试脚本,主要目的是生成mybatis最终执行的sql语句,并打印出来,方便调试。 基于此,可以实现自动化分页。
通过Mybatis拦截器自动定位慢SQL并记录日志
Mybatis 如何防止 sql 注入?mybatis 拦截器了解过吗,应用场景是什么答案 Mybatis 如何防止 sql 注入?mybatis 拦截器了解过吗,应用场景是什么答案
通过mybatis的拦截器,实现为所有sql(或指定sql) 统一添加查询条件,譬如通过线程变量传递某参数(日期),来实现对指定参数的数据筛选,而不需要在每个查询前,手动将该条件注入到查询中。因该资料网络较少,故特此...
mybatis 拦截器了解过吗,应用场景是什么.详情介绍Mybatis 如何防止 sql 注入?mybatis 拦截器了解过吗,应用场景是什么.详情介绍Mybatis 如何防止 sql 注入?mybatis 拦截器了解过吗,应用场景是什么.详情介绍...
MyBatis拦截器(csdn)————程序
spring+springMVC+mybatis拦截器分页
mybatis拦截器以及JSqlParser解析sql和生成一个新的Sqlsource
MyBatis拦截器分页代码,网上看到的,供大家一起共同分享学习。
代码包含: EscapeUtil.java:特殊字符(\,_,%)转义工具类 MyQueryInterceptor.java: Mybatis自定义拦截器 注意:该拦截器只支持QueryWrapper的like方法,serviceImpl层传全角模糊查询(%%) mapper或xml层的全角模糊查询(%...
详细介绍了Mybatis拦截器的使用,并且展示了分页插件的参考实现
mybatis mysql 分页拦截器,可以针对方法名称,或指定的参数进行拦截