本文主要分为两篇:第Ⅰ篇为MyBatis 3源码篇(第1~11章),主要介绍MyBatis框架各个特性的源码实现;第2篇章为MyBatis Spring 源码篇(第12~13章),主要介绍MyBatis框架与Spring框架整合的原理及MyBatis Spring模块的实现细节。下面是本书的内容大纲。
**第1章搭建MyBatis 源码环境,**主要介绍如何搭建MyBatis源码调试环境,包括MyBatis框架源码获取途径、如何导入集成开发工具以及如何运行 MyBatis源码中的测试用例。
**第2章JDBC规范详解,**MyBatis框架是对JDBC轻量级的封装,熟练掌握JDBC规范有助于理解MyBatis框架实现原理。本章将详细介绍JDBC规范相关细节,已经全面掌握JDBC规范的读者可以跳过该章。
**第3章MyBatis常用工具类,**介绍 MyBatis框架中常用的工具类,避免读者因对这些工具类的使用不熟悉而导致对框架主流程理解的干扰,这些工具类包括MetaObject、ObjectFactory、ProxyFactory等。
**第4章MyBatis核心组件介绍,**介绍MyBatis的核心组件,包括Configuration、SqlSession、Executor、MappedStatement等,包括这些组件的作用及 MyBatis执行SQL语句的核心流程。
**第5章SqlSession的创建过程,**本章首先介绍了XPath解析XML文件的步骤(MyBatis 的XPathParser工具类封装了JDK中XPath相关API,能够简化XML文件解析过程),以及XPathParser工具类的使用。接下来介绍了MyBatis核心组件SqlSession实例的创建过程。SqlSession实例创建之前,会使用XPathParser工具类解析MyBatis主配置文件,将配置信息转换为Configuration对象。由于SqISession 采用工厂模式创建,因此在创建SqlSession对象之前,需要先创建SqlSessionFactory对象。SqlSessionFactory对象中持有Configuration对象的引用。有了SqISessionFactory对象后,调用SqlSessionFactory对象的openSession)方法即可创建SqlSession对象。
**第6章SqlSession执行Mapper过程,**MyBatis中 Mapper的配置分为两部分,分别为Mapper接口和Mapper SQL配置。MyBatis通过动态代理的方式创建Mapper接口的代理对象,MapperProxy类中定义了Mapper方法执行时的拦截逻辑,通过MapperProxyFactory创建代理实例,MyBatis启动时,会将MapperProxyFactory注册到Configuration对象中。另外,MyBatis通过MappedStatement类描述Mapper SQL 配置信息,框架启动时,会解析Mapper SQL配置,将所有的MappedStatement对象注册到Configuration对象中。
通过Mapper代理对象调用Mapper 接口中定义的方法时,会执行MapperProxy类中的拦截逻辑,将Mapper方法的调用转换为调用SqIlSession提供的API方法。在SqlSession的API方法中通过Mapper的ld找到对应的MappedStatement对象,获取对应的SQL信息,通过StatementHandler操作JDBC的Statement对象完成与数据库的交互,然后通过ResultSetHandler处理结果集,将结果返回给调用者。
**第7章MyBatis缓存,**本章首先介绍 MyBatis一级缓存和二级缓存的使用细节,接着介绍一级缓存和二级缓存的实现原理,最后介绍 MyBatis如何整合Redis作为二级缓存。
**第8章MyBatis日志实现,**日志是Java应用中不可缺少的部分,Java语言开源的日志框架较多,比较有名的有Log4j、Logback、SLF4J等,如果搞不清这些日志框架之间的关系,就可能会造成项目中日志框架之间出现冲突,而且使用第三方框架或者工具包间接引入的日志框架会造成项目中日志输出很混乱,因此搞清楚这些日志框架之间的关系非常有必要。
本章首先介绍了Java语言中的日志体系,以及各个日志框架的发展史及它们之间的关系。接着介绍了MyBatis框架的日志实现。通过本章的学习我们了解到,MyBatis框架在未指定日志实现的情况下能够自动从 Classpath中发现日志框架,查找日志框架的顺序为SLF4J→JCL→Log4j 2→Log4j→JUL→No Logging,如果在Classpath中找到日志框架相应的JAR包,则使用该日志框架输出日志。
**第9章动态SQL实现原理,**本章首先介绍了MyBatis中动态SQL 的使用,接着介绍了动态SQL 中几个相关的概念,其中SqlSource用于描述MyBatis中的SQL资源信息,LanguageDriver用于解析SQL配置,将SQL配置信息转换为 SqlSource对象,SqINode用于描述动态SQL中<if、等标签信息,LanguageDriver解析SQL配置时,会把、等动态SQL标签转换为SqINode对象,封装在SqlSource中。而解析后的 SqlSource对象会作为MappedStatement对象的属性保存在MappedStatement对象中。执行 Mapper时,会根据传入的参数信息调用SqlSource对象的getBoundSql)方法获取BoundSql对象,这个过程就完成了将SqINode对象转换为SQL语句的过程。
本章的最后一节还介绍了MyBatis 中#{和S}参数占位符的区别,这里简单描述一下,#{占位符会被替换为“?”,然后调用JDBC中 PreparedStatement对象的setXXX()方法为参数占位符设置值,而${}占位符则会直接替换为传入的参数文本内容。
**第10章MyBatis插件原理及应用,**MyBatis提供了扩展机制,能够在执行Mapper时改变SQL的执行行为。这种扩展机制是通过拦截器来实现的,用户自定义的拦截器也被称为MyBatis插件。MyBatis框架支持对 Executor.ParameterHandler、ResultSetHandler、StatementHandler四种组件的方法进行拦截。本章介绍了MyBatis插件的实现原理,然后通过案例介绍了如何实现一个分页查询插件和慢SQL 统计插件,当读者需要的功能MyBatis框架无法满足时,可以考虑通过自定义插件来实现。
**第11章MyBatis级联映射与懒加载,**关系型数据库可以通过外键维护一对一或一对多的关系,MyBatis通过级联映射完成一对一或-对多级联查询。本章介绍了MyBatis级联映射的使用。通过本章的学习我们了解到,MyBatisMapper配置中通过标签建立一对一映射,通过标签建立一对多映射。
和标签有两种映射方式,一种方式是为Java实体属性关联一个外部的查询Mapper;另一种方式是为实体属性的每个字段配置映射,然后通过JOIN语句进行关联查询。接着本章还介绍了MyBatis的级联映射的源码实现。最后本章介绍了MyBatis懒加载机制的实现原理。
MyBatis懒加载是通过动态代理实现的,当开启懒加载配置时,调用Mapper查询的结果是通过Cglib或Javassist创建的代理对象,当调用代理对象的Getter方法获取属性值时,会执行动态代理相关的拦截逻辑,在拦截逻辑中判断实体属性是否配置了懒加载,如果是,则执行一次额外的查询来填充属性值。
**第12章MyBatis与Spring 整合案例,**在很多情况下,我们并不是单独使用MyBatis框架,而是与目前主流的loC框架Spring框架进行整合。MyBatis框架与Spring框架整合需要用到MyBatis Spring模块。本章介绍了MyBatis框架与Spring框架的整合步骤,并以一个用户注册案例介绍了MyBatis与Spring框架整合的最佳实践。学习MyBatis源码时,我们了解到,MyBatis的Mapper实例是通过动态代理创建的。
与Spring框架整合后,MyBatis 中的Mapper动态代理对象会作为Spring框架中的Bean注册到Spring容器中。第13章开始介绍MyBatis框架与Spring框架的整合原理。
**第13章MyBatis Spring 的实现原理,**MyBatis框架在大部分情况下会和目前主流的loC框架Spring 整合使用,而MyBatis框架与Spring框架的整合需要借助于MyBatis Spring模块。为了便于读者理解MyBatis与Spring框架整合的原理,本章首先介绍了Spring框架中的一些概念及Spring框架的启动过程。接着介绍了MyBatis中的 Mapper动态代理对象是如何整合到Spring容器中的。
通过本章的学习我们了解到,MyBatis与Spring框架整合后,Spring框架启动时,会扫描指定路径下的Mapper接口,将Mapper接口转换为Spring 中的 BeanDefinition对象,然后将 BeanDefinition对象的beanClass属性修改为MapperFactoryBean,这样Spring框架在所有的Bean配置转换为BeanDefinition对象后,就会根据BeanDefinition对象的beanClass属性创建Bean的实例。所以Spring框架启动后,就会为每个Mapper接口创建一个MapperFactoryBean对象,当我们通过Mapper 接口获取 Bean时,获取到的是MapperFactoryBean对象的getObject()方法返回的对象。MapperFactoryBean对象的getObject()方法中会调用SqlSession对象的getMapper()方法创建一个Mapper代理对象。
最后,本章介绍了MyBatis整合Spring事务管理的实现原理, Spring框架通过Java中的ThreadLocal机制保证同一个线程中获取到的始终是同一个Connection对象。