设为首页 收藏本站
查看: 999|回复: 0

[经验分享] Mybatis中的拦截器

[复制链接]

尚未签到

发表于 2016-11-26 06:25:05 | 显示全部楼层 |阅读模式
http://blog.csdn.net/lhch1984/article/details/6636094
http://bukebuhao.iyunv.com/blog/1338924

先看一下mybatis拦截器的用法和用途,先用为ibatis3提供基于方言(Dialect)的分页查询的例子来看一下吧!源码:
@Intercepts({@Signature(
        type= Executor.class,
        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class OffsetLimitInterceptor implements Interceptor{
    private static int    MAPPED_STATEMENT_INDEX    = 0;
    private static int    PARAMETER_INDEX            = 1;
    private static int    ROWBOUNDS_INDEX            = 2;
    private Dialect        dialect;
   
    public Object intercept(Invocation invocation) throws Throwable {
        processIntercept(invocation.getArgs());
        return invocation.proceed();
    }

    private void processIntercept(final Object[] queryArgs) {
        //queryArgs = query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)
        MappedStatement ms = (MappedStatement)queryArgs[MAPPED_STATEMENT_INDEX];
        Object parameter = queryArgs[PARAMETER_INDEX];
        final RowBounds rowBounds = (RowBounds)queryArgs[ROWBOUNDS_INDEX];
        int offset = rowBounds.getOffset();
        int limit = rowBounds.getLimit();
      
        if(dialect.supportsLimit() && (offset != RowBounds.NO_ROW_OFFSET || limit != RowBounds.NO_ROW_LIMIT)) {
            BoundSql boundSql = ms.getBoundSql(parameter);
            String sql = boundSql.getSql().trim();
            if (dialect.supportsLimitOffset()) {
                sql = dialect.getLimitString(sql, offset, limit);
                offset = RowBounds.NO_ROW_OFFSET;
            } else {
                sql = dialect.getLimitString(sql, 0, limit);
            }
            limit = RowBounds.NO_ROW_LIMIT;
           
            queryArgs[ROWBOUNDS_INDEX] = new RowBounds(offset,limit);
            BoundSql newBoundSql = new BoundSql(ms.getConfiguration(),sql, boundSql.getParameterMappings(), boundSql.getParameterObject());
            MappedStatement newMs = copyFromMappedStatement(ms, new BoundSqlSqlSource(newBoundSql));
            queryArgs[MAPPED_STATEMENT_INDEX] = newMs;
        }
    }
   
    //see: MapperBuilderAssistant
    private MappedStatement copyFromMappedStatement(MappedStatement ms,SqlSource newSqlSource) {
        Builder builder = new MappedStatement.Builder(ms.getConfiguration(),ms.getId(),newSqlSource,ms.getSqlCommandType());
      
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        builder.keyProperty(ms.getKeyProperty());
      
        //setStatementTimeout()
        builder.timeout(ms.getTimeout());
      
        //setStatementResultMap()
        builder.parameterMap(ms.getParameterMap());
      
        //setStatementResultMap()
        builder.resultMaps(ms.getResultMaps());
        builder.resultSetType(ms.getResultSetType());
      
        //setStatementCache()
        builder.cache(ms.getCache());
        builder.flushCacheRequired(ms.isFlushCacheRequired());
        builder.useCache(ms.isUseCache());
      
        return builder.build();
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties properties) {
        String dialectClass = properties.getProperty("dialectClass");
        try {
            dialect = (Dialect)Class.forName(dialectClass).newInstance();
        } catch (Exception e) {
            throw new IllegalArgumentException(
                    "cannot create dialect instance by dialectClass:"
                            + dialectClass, e);
        }
    }
   
    public static class BoundSqlSqlSource implements SqlSource {

        private BoundSql    boundSql;

        public BoundSqlSqlSource(BoundSql boundSql) {
            this.boundSql = boundSql;
        }

        public BoundSql getBoundSql(Object parameterObject) {
            return boundSql;
        }
    }
}
      注解Intercepts表示该类被用作拦截器,@Signature(type= Executor.class,       method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})用来表示拦截那个类得那个方法,拦截器可用于Executor,ParameterHandler,ResultSetHandler和StatementHandler这些类上。
       我们看看这个拦截器是怎么拦截Executor的qurey方法的。先看生成Executor对象的过程:
       我们从这个序列图中可以清晰的看出,我们最后得到的Executor是一个代理对象。返回的这个Executor的代理对象是将Plugin作为调用处理器的,我们看一下Plugin的invoke方法:
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);
    }
  }
        这个方法中需要提的就是signatureMap,我们看看这个signatureMap是怎么取得的,我们看到是从wrap方法中通过getSignatureMap(interceptor)得到的,getSignatureMap方法源码:
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
    Signature[] sigs = interceptor.getClass().getAnnotation(Intercepts.class).value();
    Map<Class<?>, Set<Method>> signatureMap = new HashMap<Class<?>, Set<Method>>();
    for (Signature sig : sigs) {
      Set<Method> methods = signatureMap.get(sig.type());
      if (methods == null) {
        methods = new HashSet<Method>();
        signatureMap.put(sig.type(), methods);
      }
      try {
        Method method = sig.type().getMethod(sig.method(), sig.args());
        methods.add(method);
      } catch (NoSuchMethodException e) {
        throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
      }
    }
    return signatureMap;
  }
       这个方法就是解析各个迭代器的标注,得到一个以被拦截的对象为key,以被拦截的方法集为值得value的Map。从上面这些源码我们可以了解,mybatis是将plugin已经做方法调用处理器,将目标对象一层层的做代理,在执行的时候判断方法是否在signatureMap中注册(也就是@Signature( type= Executor.class,        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))标注了没有),如果注册了就执行拦截器中的intercept方法。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-305558-1-1.html 上篇帖子: mybatis多参数传入问题 下篇帖子: mybatis 调用存在过程
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表