java MyBatis拦截器Inteceptor详细介绍

网友投稿 210 2023-06-30


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 newStatementHandlhttp://er(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, 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, Set> 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 Ohttp://bject invoke(Object proxy, Method method, Object[] args) throws Throwable {

try {

Set 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)。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:EDI中JAVA通过FTP工具实现文件上传下载实例
下一篇:EasyUI 中combotree 默认不能选择父节点的实现方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~