`
amigo
  • 浏览: 50739 次
  • 来自: ...
社区版块
存档分类
最新评论

Mybatis中的拦截器

 
阅读更多
http://blog.csdn.net/lhch1984/article/details/6636094
http://bukebuhao.iteye.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方法。
分享到:
评论

相关推荐

    mybatis分页拦截器(自动封装版)剖析.pdf

    在自动封装版的MyBatis分页拦截器中,开发者通常会创建一个拦截器类,该类会拦截到执行SQL的时机,然后在SQL语句中动态添加分页相关的条件,如LIMIT和OFFSET子句,以实现数据的分页展示。 分页拦截器的核心思想是...

    Mybatis分页拦截器

    在Mybatis中,拦截器扮演着插件的角色,可以监听并修改Mybatis执行过程中的某些行为。本话题将深入探讨Mybatis分页拦截器的工作原理、实现方式以及在不同版本(如mybatis-3.1.1和mybatis-3.0.4)下的兼容性。 首先...

    mybatis拦截器实现通用权限字段添加的方法

    要使用MyBatis拦截器,我们需要在Spring配置文件中添加拦截器的配置。 ```xml &lt;bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"&gt; &lt;value&gt;classpath*:xmlmapper/*.xml ...

    mybatis 分页拦截器及拦截器配置

    在分页拦截器中,它会在执行查询之前对SQL进行修改,自动添加LIMIT和OFFSET子句,从而实现分页查询。 首先,我们要引入一个分页插件,例如PageHelper或者MyBatis-Plus。这两个都是广受欢迎的MyBatis分页插件,它们...

    mybatis使用拦截器实现分页操作

    MyBatis拦截器类似于Java的AOP(面向切面编程)中的拦截器,它可以在特定的方法调用前后插入自定义的行为。在MyBatis中,我们可以通过实现`org.apache.ibatis.plugin.Interceptor`接口并重写`intercept`方法来创建一...

    Mybatis自定义拦截器,对模糊查询传值的特殊字符(\,_,%)统一进行转义处理的代码

    代码包含: EscapeUtil.java:特殊字符(\,_,%)转义工具类 MyQueryInterceptor.java: Mybatis自定义拦截器 注意:该拦截器只支持QueryWrapper的like方法,serviceImpl层传全角模糊查询(%%) mapper或xml层的全角模糊查询(%...

    Mybatis自定义拦截器,对模糊查询传值的特殊字符统一进行转义处理的代码

    特殊字符(\,_,%)转义工具类 MyQueryInterceptor.java: Mybatis自定义拦截器 注意:该拦截器只支持QueryWrapper的like方法,serviceImpl层传全角模糊查询(%%) mapper或xml层的全角模糊查询(%*%)和半角模糊查询(%*或*%)

    MyBatis拦截器:给参数对象属性赋值的实例

    MyBatis拦截器是MyBatis框架中的一种插件机制,允许用户自定义代码来扩展MyBatis的功能。在这个特定的实例中,我们讨论的是一个用于给参数对象属性赋值的拦截器。这个拦截器的主要目标是在执行增删改操作时,自动为...

    通过Mybatis拦截器自动定位慢SQL并记录日志

    下面我们将详细介绍如何通过Mybatis拦截器实现这一功能。 首先,了解Mybatis拦截器的基本概念。Mybatis拦截器(Interceptor)是一种插件机制,它允许我们在Mybatis执行SQL语句之前或之后进行自定义操作,比如统计...

    MyBatis拦截器分页与动态修改SQL及其参数值

    在"MyBatis拦截器分页与动态修改SQL及其参数值"的主题中,我们可以深入理解以下几个关键知识点: 1. **MyBatis拦截器**:MyBatis提供了一种插件机制,即拦截器(Interceptor),它基于Java的动态代理,可以在SQL...

    MyBatis拦截器 添加查询条件动态修改sql

    通过mybatis的拦截器,实现为所有sql(或指定sql) 统一添加查询条件,譬如通过线程变量传递某参数(日期),来实现对指定参数的数据筛选,而不需要在每个查询前,手动将该条件注入到查询中。因该资料网络较少,故特此...

    mybatis分页拦截器

    在分页拦截器中,我们通常在这个方法中处理分页逻辑。 2. **配置拦截器**:在MyBatis的配置文件中,我们需要声明并配置拦截器,指定其类名以及可能的参数,例如分页插件的属性,如当前页数、每页记录数等。 3. **...

    Mybatis拦截器记录数据更新历史记录到MongoDB

    接着,在应用启动时初始化MongoDB的连接,并在拦截器中使用这个连接实例来执行插入操作。 最后,关于MongoDB的使用,需要注意其文档模型与传统关系型数据库的区别。MongoDB的文档是以BSON(Binary JSON)格式存储的...

    mybatis拦截器修改执行sql语句

    通过mybatis拦截器将查询语句、更新语句、删除语句、插入语句中指定表明替换为另一个表名

    Mybatis中拦截器的简单实现方法

    在介绍Mybatis拦截器的实现之前,先来回顾一下JDK动态代理的基本原理。动态代理机制主要涉及到Java的java.lang.reflect包,它允许程序在运行期间创建接口的代理实例。通过Proxy类与InvocationHandler接口,可以在...

    mybatis拦截器的完整实现

    MyBatis拦截器是MyBatis框架中一个强大的特性,它允许我们在MyBatis执行SQL语句前后插入自定义逻辑,比如日志记录、性能分析、动态修改SQL等。在这个"mybatis拦截器的完整实现"项目中,我们可以通过设置拦截器来观察...

    MyBatis拦截器分页

    MyBatis拦截器分页是实现数据库查询优化和提高应用性能的一种有效手段。在MyBatis框架中,拦截器扮演着动态代理的角色,允许我们在执行SQL之前或之后进行额外的操作,比如统计、日志记录或者在本例中的分页处理。...

Global site tag (gtag.js) - Google Analytics