虚位以待(AD)
虚位以待(AD)
首页 > 软件编程 > Java编程 > java MyBatis拦截器Inteceptor详细介绍

java MyBatis拦截器Inteceptor详细介绍
类别:Java编程   作者:码皇   来源:互联网   点击:

这篇文章主要介绍了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, 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<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)。

相关热词搜索: java MyBatis拦截器Inteceptor java MyBat