`
bukebuhao
  • 浏览: 88440 次
  • 性别: Icon_minigender_1
  • 来自: 绍兴
社区版块
存档分类
最新评论

mybatis的拦截器interceptor源代码解析

阅读更多

mybatis支持拦截器,实现的原理就是利用JDK的动态代理。先前利用拦截器实现了分页功能,如今又利用拦截器实现日志记录的功能,感觉拦截器还是不错的,只是相对于spring3 mvc的拦截器感觉有些逊色。接下来,我着重分析一些拦截的使用。

【基本思路】拦截器在哪里拦截?什么情况下才会拦截代理?怎么代理呢?只要搞清楚这些,基本的拦截器功能也就了如指掌啦。
拦截器在哪里呢?mybatis到底提供几处可以拦截呢?请看下图,通过分析源码可知基本查询流程如下:
mybatis的interceptor拦截器流程图
【简洁的流程】 首先mybatis初始化加载的时候,利用 MapperProxy代理 自己的Mapper接口类, 生成一个代理处理类,代理处理的逻辑都在 invoke方法里,首先获取到目标类的接口 declaringInterface,然后生成 MapperMethod,(其中 sqlSession是 SqlSessionTemplate,是spring连接mybatis的模板类,是由spring负责生成的),生成了 MapperMethod,直接调用 MapperMethod可执行的方法 execute就能获取执行结果,整个流程非常简洁,非常和spring3 mvc的servlet实现类似,也就是说, MapperMethod就是一个命令,执行命令获取执行结果,也就是标准的命令模式。整个流程代码如下:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (method.getDeclaringClass() == Object.class) {
      return method.invoke(this, args);
    }
    final Class<?> declaringInterface = findDeclaringInterface(proxy, method);
    final MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, sqlSession);
    final Object result = mapperMethod.execute(args);
    if (result == null && method.getReturnType().isPrimitive() 
       && !method.getReturnType().equals(Void.TYPE)) {
      throw new BindingException(
      "Mapper method '" + method.getName() + "' (" + method.getDeclaringClass() 
      + ") attempted to return null from a method with a primitive return type (" 
      + method.getReturnType() + ").");
    }
    return result;
  } 
  

【分步分析】
  • MapperMethod
查看excute方法可知,就是根据不同的sql类型,交给sqlSession,也就是SqlSessionTemplate类的对象,主要是完成获取执行参数 param commandName,执行具体的操作,例如, result =   sqlSession . selectList ( commandName , param); 其中sql类型的获取可参考初始化的时候加载的setupCommandType(),初始化的时候还包括获取map的sqlID等
  • SqlSessionTemplate和 SqlSessionInterceptor
利用eclipse的f4一下,可知 SqlSessionTemplate的实际执行是交给它的代理类完成的。查看 SqlSessionTemplate构造函数可知,是由 SqlSessionInterceptor动态代理的,那么所有的处理逻辑都是在 invoke方法里,从中可知,就是获取SqlSession,执行操作。其中 SqlSessionUtils . getSqlSession静态方法调用外部类 SqlSessionTemplate SqlSessionFactory, ExecutorType,这些都是在mybatis加载 SqlSessionTemplate 构造函数初始化的。
  • DefaultSqlSession
这个就是从 DefaultSqlSessionFactory工厂生成获取的,具体的加载流程就是在 sqlSession . selectList静态方法里。
接着上面的查询流程可知,调用的 selectList方法,通过 MapperMethod方法中获取的 commandName,获取到 MappedStatement对象,主要负责的就是sql里xml信息等,具体执行交给 executor, executor是由 SqlSessionTemplate的 ExecutorType决定的。
  • executor和 Plugin
executor的获取是 DefaultSqlSessionFactory生成 DefaultSqlSession,加载的方法是在 Configuration里 newExecutor从中可知 cacheEnabled默认为ture,追加缓存实现,具体的实现还是 SimpleExecutor,属于静态代理, cacheEnabled只是 实现了缓存功能。 executor = (Executor)   interceptorChain .pluginAll(executor);
表明可追加拦截器。查看代码可知,
 
  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }  
 
就是调用拦截Interceptor的方法plugin,我们在plugin方法里一般都需要调用Plugin的静态方法wrap生成Plugin动态代理目标类,由于又是动态代理,实现逻辑都是在invoke方法里,查看可知,调用Interceptor的intercept方法,由Invoction封装目标类,调用方法,调用参数。因此,我们实现自己的拦截器的时候,都可从intercept方法里获取到拦截的对象,方法,参数等。这里其中涉及到两个问题就是拦截器什么情况下才会代理的,怎样代理呢。第一个问题,查看wrap方法可知,就是查看Map里查找是否设定代理啦,以代理对象的class做为key,代理方法的set集合作为value,就能判定是否要代理的。Map里的数据是遍历拦截器的注解Intercepts,实现很简单。怎样打理的,就是调用Interceptor的intercept方法,具体的实现都是在自定义的拦截器方法里。
  • StatementHandler, ParameterHandler,  ResultSetHandler和 Plugin
SimpleExecutor的 doQuery方法是具体的实现, 获取StatementHandler,然后通过StatementHandler获取Statement,其中 StatementHandler的获取又是在Configuration里newStatementHandler,同executor实现的类似,也是有RoutingStatementHandler代理实际的StatementHandler实现,通过StatementType获取具体的StatementHandler类,从默认配置可知,PreparedStatementHandler是实际代理的对象。这里也有 executor = (Executor)  interceptorChain .pluginAll(executor)可知 同样可添加拦截器。其中构造StatementHandler的时候,查看BaseStatementHandler构造函数可知,ParameterHandler和ResultSetHandler也是有Configuration生成的,同样也可追加拦截器。
  • Statement和日志代理
SimpleExecutor的 doQuery方法调用 prepareStatement 可知, Statement获取是通过StatementHandler的prepare方法生成的,由于PreparedStatementHandler是具体的实现类,查看可知,instantiateStatement方法里是具体的获取Statement方法,由ConnectionLogger代理类调用PreparedStatementLogger.newInstance生成PreparedStatementLogger。其中ConnectionLogger是DefaultSqlSessionFactory里wrapConnection方法获取的。
【总结】
mybatis的拦截器都是在 Configuration类的 InterceptorChain负责调用位置,Plugin类负责生成代理,调用具体的拦截器实现类





分享到:
评论

相关推荐

    mybatis拦截器的完整实现

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

    SpringBoot整合Mybatis完整详细版含注册、登录、拦截器配置

    在本项目中,我们主要探讨的是如何将SpringBoot与Mybatis进行深度整合,并实现完整的注册、登录功能,以及设置拦截器来控制权限访问。SpringBoot以其简洁的配置和快速的开发能力,配合Mybatis的灵活数据库操作,可以...

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

    1. 将Java源代码中的拦截器类放置到项目合适的包结构下。 2. 在Maven或Gradle等构建工具的配置文件中添加MyBatis的相关依赖。 3. 配置Spring MyBatis的XML文件,声明并启用拦截器插件,通常需要指定拦截器类和相关...

    Mybatis分页拦截器

    这两个类都是实现了`Interceptor`接口的自定义拦截器,它们在Mybatis的执行流程中插入,对SqlSession的执行过程进行拦截,从而实现分页功能。 首先,`MybatisSpringPageInterceptor`通常用于Spring Boot集成Mybatis...

    Mybatis拦截器介绍及分页插件.pdf

    ### Mybatis拦截器介绍及分页插件 #### 1.1 前言与概述 在探讨Mybatis拦截器及其分页插件之前,我们首先需要了解什么是拦截器以及为何要在Mybatis中使用它。 **拦截器**是一种设计模式,它允许在执行某个操作前或...

    mybatis3 物理分页源代码

    最后,配置Mybatis拦截器。在`mybatis-config.xml`中,你需要添加一个`plugins`节点,里面包含你的分页插件配置: ```xml ... &lt;plugin interceptor="com.example.PaginationInterceptor"&gt; &lt;!-- 可选的配置项...

    SpringMVC+Mybatis+Mysql+权限+拦截器的整合实例 源码程序

    在本项目中,我们主要探讨的是一个基于SpringMVC、Mybatis、Mysql数据库的完整应用实例,同时涉及到了权限管理和拦截器的实现。这个实例提供了详细的源代码,包括SQL脚本,以及一些实用的工具类,使得开发者可以快速...

    Spring Boot集成Mybatis附加自动生成工具,异常信息处理等工具类,拦截器,最全框架

    拦截器(Interceptor)在Spring Boot和Mybatis的整合中扮演着重要角色。它可以拦截请求,进行权限验证、日志记录、性能统计等操作。通过实现`HandlerInterceptor`接口并注册到Spring容器,开发者可以定制化地处理...

    Mybatis Interceptor 拦截器的实现

    Mybatis 提供了四种类型的拦截器:Executor、ParameterHandler、ResultSetHandler、StatementHandler,这些类中的方法细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码。 Interceptor...

    mybatis-3.2.2-src.rar 源码

    这个源码包"mybatis-3.2.2-src.rar"包含了完整的Mybatis 3.2.2版本的源代码,对开发者来说是一份宝贵的学习资源。 源码分析可以从以下几个主要方面展开: 1. **架构设计**:Mybatis 的核心组件包括...

    spring+mybatis 数据路由源代码

    5. 拦截器:在Mybatis中,可能通过MapperScannerConfigurer或Interceptor实现SQL执行的拦截,从而在执行SQL前改变当前的数据源。 "说明文档.docx"文件可能包含了项目的详细使用说明、配置示例、以及自定义规则的...

    MyBatis源码包

    6. **插件机制**:通过Interceptor插件,用户可以自定义拦截器实现对SQL执行过程的拦截和修改。 7. **配置文件解析**:XmlConfigBuilder和JavaConfigBuilder负责解析MyBatis的XML配置文件和Java配置类。 8. **日志...

    Mybatis源码(4)-拦截器.pdf

    通过这种方式,Mybatis的拦截器机制可以深入到数据访问的各个层次,为开发者提供了极大的灵活性,使得在不修改源代码的情况下,能够对Mybatis的行为进行扩展和定制。开发者可以根据实际需求,创建自己的拦截器,例如...

    Mybatis-3完整版源代码java-source-code

    这个资源" Mybatis-3 完整版源代码 java-source-code"包含了 Mybatis 3.x 版本的核心源码,这对于深入理解其工作原理、学习如何自定义拦截器、插件以及优化 SQL 查询非常有帮助。 首先,我们来探讨一下 Mybatis 的...

    mybatis3.4.4的jar包及其源代码

    而`mybatis-3-mybatis-3.4.4.zip`可能是包含MyBatis源代码的文件,对于学习和理解MyBatis的内部工作机制非常有帮助,可以查看其具体实现,包括SQL解析、动态SQL生成等核心功能。 通过深入学习和研究这两个文件,...

    MyBatis 3.4.1 jar包和源代码

    6. **插件机制**:通过实现`Interceptor`接口,开发者可以创建自定义插件,对MyBatis的执行过程进行拦截和修改,例如添加日志、性能分析等功能。 7. **事务管理**:MyBatis提供了基于JDBC的事务管理,开发者可以...

    SSM+拦截器分页

    在实际项目中,为了提高用户体验,我们通常需要实现数据的分页展示,而拦截器(Interceptor)则是SSM中一种重要的功能,用于增强或控制程序的执行流程。本文将详细介绍如何在SSM框架中结合拦截器实现分页功能。 ...

    Struts2+Spring3.1+MyBatis3.06+EasyUI整合

    它解决了JSP中的Action和业务逻辑分离的问题,提供了强大的请求处理机制和拦截器(Interceptor)体系,使开发者可以自定义行为和拦截特定请求。在整合中,Struts2作为前端控制器,负责接收用户请求,调度到相应的...

    Spring Boot 整合Mybatis、Druid、PageHelper、Swagger 、AOP、过滤器、拦截器、thymeleaf 基础入门demo

    **Spring Boot整合Mybatis、Druid、PageHelper、Swagger、AOP、过滤器与拦截器、Thymeleaf基础入门** 在现代Java开发中,Spring Boot以其简洁的配置和强大的功能,成为了主流的微服务框架。这个入门示例将帮助我们...

    MyBatis插件

    完成后,MBG会按照配置生成相应的Java源代码。 总结来说,MyBatis插件是MyBatis框架的一个强大特性,它们允许开发者对MyBatis的行为进行扩展和定制。通过创建自定义的拦截器,我们可以实现诸如日志记录、性能监控等...

Global site tag (gtag.js) - Google Analytics