阅读mybatis源码,掌握这几步就够了
对于源码,很多人不知道如何看,今天来教教大家如何看源码。
前提是我们需要对整个Mybatis的原理、工作流程和模块进行一个整体的直知晓,另外还要有使用经验。
本文主要内容:
源码下载
如何下载源码?
进入官网
https://mybatis.org/mybatis-3/zh/index.html
方法一
跳转到github上,我们可以在github上下源码
https://github.com/mybatis/mybatis-3
下载源码
方法二
也可以通过
https://github.com/mybatis/mybatis-3/releases
下载对应版本jar和源码:
下载到本地后,解压到自己的本地目录,然后使用eclipse或者IDEA导入。
发现Mybatis的包目录多大20个,下面我们就来说说这些包的关系和对应的作用。
包分成三大类
基础功能包
这些包用来为其他包提供一些外围基础功能,如文件读取功能、反射操作功能等。这些包的特点是功能相对独立,与业务逻辑耦合小。
下面就是基础功能相关的包目录:
配置解析包
这些包用来完成配置解析、存储等工作。这些包中的方法主要在系统初始化阶段运行。
下面就是配置相关的包目录:
核心操作包
这些包用来完成数据库操作。在工作过程中,这些包可能会依赖基础功能包提供的基础功能和配置解析包提供的配置信息。这些包中的方法主要在数据库操作阶段运行。
核心处理层主要做了这四件事:
把接口中传入的参数解析并映射成JDBC类型;
解析xml文件中的SQL语句,包括插入参数和动态SQL的生成;
执行SQL语句;
处理结果集,并映射成Java对象。
注意:插件也属于核心层,这是由它的工作方式和拦截的对象决定的。
下面就是核心层对应的包目录:
具体包介绍
reflection 包
Java 中的反射虽然功能强大,但对大多数开发人员来说,写出高质量的反射代码还是 有一定难度的。
MyBatis 中专门提供了反射模块,该模块对 Java 原生的反射进行了良好的封装,提了更加简洁易用的 API,方便上层调用,并且对反射操作进行了一系列优化,例如缓存了类的元数据,提高了反射操作的性能。
Java反射机制主要提供了以下功能。· 在运行时判断任意一个对象所属的类;· 在运行时构造任意一个类的对象;· 在运行时修改任意一个对象的成员变量;· 在运行时调用任意一个对象的方法。
推荐一篇反射的文章:
type 包
① MyBatis 为简化配置文件提供了别名机制,该机制是类型转换模块的主要功能之一。
② 类型转换模块的另一个功能是实现 JDBC 类型与 Java 类型之间的转换,该功能在为 SQL 语句绑定实参以及映射查询结果集时都会涉及:
在为 SQL 语句绑定实参时,会将数据由 Java 类型转换成 JDBC 类型。
而在映射结果集时,会将数据由 JDBC 类型转换成 Java 类型。
logging 包
无论在开发测试环境中,还是在线上生产环境中,日志在整个系统中的地位都是非常重要的。良好的日志功能可以帮助开发人员和测试人员快速定位 Bug 代码,也可以帮助运维人员快速定位性能瓶颈等问题。目前的 Java 世界中存在很多优秀的日志框架,例如 Log4j、 Log4j2、Slf4j 等。
MyBatis 作为一个设计优良的框架,除了提供详细的日志输出信息,还要能够集成多种日志框架,其日志模块的一个主要功能就是集成第三方日志框架。
io 包
资源加载模块,主要是对类加载器进行封装,确定类加载器的使用顺序,并提供了加载类文件以及其他资源文件的功能 。
parsing 包
顾名思义解析器模块,主要提供了两个功能:
一个功能,是对 XPath进行封装,为 MyBatis 初始化时解析 mybatis-config.xml 配置文件以及映射配置文件提供支持。
另一个功能,是为处理动态 SQL 语句中的占位符提供支持。
datasource 包
数据源是实际开发中常用的组件之一。现在开源的数据源都提供了比较丰富的功能,例如,连接池功能、检测连接状态等,选择性能优秀的数据源组件对于提升 ORM 框架乃至整个应用的性能都是非常重要的。
MyBatis 自身提供了相应的数据源实现,当然 MyBatis 也提供了与第三方数据源集成的接口,这些功能都位于数据源模块之中。
transaction 包
MyBatis 对数据库中的事务进行了抽象,其自身提供了相应的事务接口和简单实现。在很多场景中,MyBatis 会与 Spring 框架集成,并由 Spring 框架管理事务。
cache 包
在优化系统性能时,优化数据库性能是非常重要的一个环节,而添加缓存则是优化数据库时最有效的手段之一。正确、合理地使用缓存可以将一部分数据库请求拦截在缓存这一层。
MyBatis 中提供了一级缓存和二级缓存,而这两级缓存都是依赖于基础支持层中的缓 存模块实现的。这里需要读者注意的是,MyBatis 中自带的这两级缓存与 MyBatis 以及整个应用是运行在同一个 JVM 中的,共享同一块堆内存。如果这两级缓存中的数据量较大, 则可能影响系统中其他功能的运行,所以当需要缓存大量数据时,优先考虑使用 Redis、Memcache 等缓存产品。
binding 包
在调用 SqlSession 相应方法执行数据库操作时,需要指定映射文件中定义的 SQL 节点,如果出现拼写错误,我们只能在运行时才能发现相应的异常。为了尽早发现这种错误,MyBatis 通过 Binding 模块,将用户自定义的 Mapper 接口与映射配置文件关联起来,系统可以通过调用自定义 Mapper 接口中的方法执行相应的 SQL 语句完成数据库操作,从而避免上述问题。
值得读者注意的是,开发人员无须编写自定义 Mapper 接口的实现,MyBatis 会自动为其创建动态代理对象。在有些场景中,自定义 Mapper 接口可以完全代替映射配置文件,但有的映射规则和 SQL 语句的定义还是写在映射配置文件中比较方便,例如动态 SQL 语句的定义。
annotations 包
随着 Java 注解的慢慢流行,MyBatis 提供了注解的方式,使得我们方便的在 Mapper 接口上编写简单的数据库 SQL 操作代码,而无需像之前一样,必须编写 SQL 在 XML 格式的 Mapper 文件中。虽然说,实际场景下,大家还是喜欢在 XML 格式的 Mapper 文件中编写相应的 SQL 操作。
exceptions 包
exceptions包中有三个与Exception相关的类:
IbatisException类(已经设置为不推荐使用了)、
PersistenceException类
TooManyResultsException类
在 MyBatis的其他包中,还有许多异常类。这些异常类中除 RuntimeSqlException类外,均为 PersistenceException的子类。
MyBatis中异常类类图:
几乎每个都有阈值对应的自定义异常。
scripting 包
拼凑 SQL 语句是一件烦琐且易出错的过程,为了将开发人员从这项枯燥无趣的工作中 解脱出来,MyBatis 实现动态 SQL 语句的功能,提供了多种动态 SQL语句对应的节点。例如
MyBatis 中的 scripting 模块,会根据用户传入的实参,解析映射文件中定义的动态 SQL 节点,并形成数据库可执行的 SQL 语句。之后会处理 SQL 语句中的占位符,绑定用户传入的实参。
plugin 包
Mybatis 自身的功能虽然强大,但是并不能完美切合所有的应用场景,因此 MyBatis 提供了插件接口,我们可以通过添加用户自定义插件的方式对 MyBatis 进行扩展。用户自定义插件也可以改变 Mybatis 的默认行为,例如,我们可以拦截 SQL 语句并对其进行重写。
由于用户自定义插件会影响 MyBatis 的核心行为,在使用自定义插件之前,开发人员需要了解 MyBatis 内部的原理,这样才能编写出安全、高效的插件。
session 包
接口层相对简单,其核心是 SqlSession 接口,该接口中定义了 MyBatis 暴露给应用程序调用的 API,也就是上层应用与 MyBatis 交互的桥梁。接口层在接收到调用请求时,会调用核心处理层的相应模块来完成具体的数据库操作。
executor包
主要负责维护一级缓存和二级缓存,并提供事务管理的相关操作,它会将数据库相关操作委托给 StatementHandler完成。
mapping包
mapping主要是SQL操作解析后的映射
builder包
builder是配置和注解的解析过程。
cursor包
处理游标相关的代码。实话实说,工作中用到很少,所以这里就不展开介绍。
jdbc 包
生成JDBC能处理的语句 。
lang包
指定使用Java7还是Java8的API的注解。
总结
面对如何看源码,很多人都无从下手,有的人也是瞎搞,到最后肯定看一点点就放弃了。
对于看源码的套路,个人建议:
1.学会使用,必须要熟练使用;
2.先掌握一些常见的设计模式(工厂模式、单列模式、模板方法模式、装饰器模式、代理模式等);
3.熟悉设计原理;
4.熟悉源代码的这个包目录,以及每个包的大致功能;
5.多思考为什么是这样;
6.王者模式:既然你会用了,那么如果让你来设计,你会怎么设计?