java MyBatis拦截器Inteceptor详细介绍
发布时间:2020-12-30 16:13:31 所属栏目:Java 来源:互联网
导读:有许多java初学者对于MyBatis拦截器Inteceptor不是很了解,在这里我来为各位整理下篇关于java中MyBatis拦截器Inteceptor详解,
|
有许多java初学者对于MyBatis拦截器Inteceptor不是很了解,在这里我来为各位整理下篇关于java中MyBatis拦截器Inteceptor详解, 本文主要分析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 ParameterHandler newParameterHandler(MappedStatement mappedStatement,Object parameterObject,BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement,parameterObject,boundSql);
/* 拦截ParameterHandler*/
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public ResultSetHandler newResultSetHandler(Executor executor,MappedStatement mappedStatement,RowBounds rowBounds,ParameterHandler parameterHandler,ResultHandler resultHandler,BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor,mappedStatement,parameterHandler,resultHandler,boundSql,rowBounds);
/* 拦截ResultSetHandler*/
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
public StatementHandler newStatementHandler(Executor executor,BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor,rowBounds,boundSql);
/* 拦截StatementHandler*/
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
public Executor newExecutor(Transaction transaction,ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this,transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this,transaction);
} else {
executor = new SimpleExecutor(this,transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
/* 拦截Executor*/
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
实现一个自定义拦截器只需实现Interceptor接口即可,大致代码如下: 代码如下
/* 注解表明要拦截哪个接口的方法及其参数 */
@Intercepts({ @Signature(type = StatementHandler.class,method = "prepare",args = { Connection.class }) })
public class YourInterceptor implements Interceptor{
public Object intercept(Invocation invocation) throws Throwable{
doSomeThing();
/* 注:此处实际上使用Invocation.proceed()方法完成interceptorChain链的遍历调用(即执行所有注册的Interceptor的intercept方法),到最终被代理对象的原始方法调用 */
return invocation.proceed();
}
/*生成成对目标target的代理,而@Intercepts的注解是在Plugin.wrap中用到*/
@Override
public Object plugin(Object target){
/* 当目标类是StatementHandler类型时,才包装目标类,不做无意义的代理 */
return (target instanceof StatementHandler)?Plugin.wrap(target,this):target;
}
/*用于设置自定义的拦截器配置参数*/
@Override
public void setProperties(Properties properties){
}
}
其中,拦截调用的代码均在Plugin.wrap中: 代码如下
/* org.apache.ibatis.plugin.Plugin类 */
public class Plugin implements InvocationHandler {
/* 省略代码... */
public static Object wrap(Object target,Interceptor interceptor) {
/* 此处即为获取Interceptor的注解签名 */
Map<Class<?>,Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
/* 获取拦截目标类相匹配的接口 */
Class<?>[] interfaces = getAllInterfaces(type,signatureMap);
if (interfaces.length > 0) {
/* 使用jdk动态代理 */
return Proxy.newProxyInstance(type.getClassLoader(),interfaces,new Plugin(target,interceptor,signatureMap));
}
return target;
}
/* 拦截目标类的所有方法的执行都会变为在此执行 */
@Override
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
try {
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
/* 执行拦截器方法 */
return interceptor.intercept(new Invocation(target,method,args));
}
return method.invoke(target,args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
/* 省略代码... */
}
可以看到MyBatis的拦截器设计核心代码还是比较简单的,但是足够灵活。实际使用时注意,不做无意义的代理(Plugin.wrap)。 (编辑:哈尔滨站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
