在历经之前几章课程的深入学习之后,我想我们已经初步掌握了如何运用jdbc连接数据库的技术;同时,我们也实现了利用mybatis框架的能力,甚至尝试着手编写、实现了ORM的框架。我坚信大家对MyBatis的理解和应用已经达到了一定程度。然而,你们是否有思考过为何MyBatis能够具备如此强大的效能呢?因此,在本次课程中,我们将全面剖析MyBatis的源代码,以此揭示其背后隐藏着的卓越功能的实现原理。为了方便我们的Debug实验,我们仍然会参考并使用在上一章节课程所提到的Mybatis-Demo模块进行操作。
在接下来的探究过程中,我们首要需要的就是MyBatis的源代码。建议各位同学可以登录mybatis官方网站获取并下载该源代码(地址为:https://github.com/mybatis/mybatis-3)。
我们首先可以看到我们的启动类是这样的
package com.masiyi;
import com.masiyi.dao.UserDao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* @Author masiyi
* @Date ${DATE}
* @PackageName:com.masiyi
* @ClassName: ${NAME}
* @Description: TODO
* @Version 1.0
*/
public class Main {
public static void main(String[] args) throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession session = sqlSessionFactory.openSession()) {
UserDao mapper = session.getMapper(UserDao.class);
mapper.findById(1).forEach(System.out::println);
System.out.println("----------------------------");
mapper.findAll().forEach(System.out::println);
}
}
}
就和上一篇文章一样。第一行的意思就是引入我们的mybatis的配置文件。这个配置文件要在我们的resource资源目录下面。我们现在去看这个resource类做了哪些动作?
经过这个方法之后,我们可以看到他需要调类加载器的getResourceAsStream这个方法。
最终把我们的传进来这个字符串给转化为url。
实际上他根据我们的类加载器找到了这个配置文件在我们本机环境下的绝对路径。这样他就能根据绝对路径转化为一个输入流。方便我们后续的读配置文件的要求。
运行完第一行之后,我们的目的就完成了,他最终给我们的是一个输入流。
第二行我们可以看到它其实进入了一个build的重载方法。第二个参数和第三个参数全都是null,他也就是说只传入了我们第一行代码,给过我们的输入流。通过我们的输入流,他给我们建造了一个XMLConfigBuilder对象。这个对象的目的就是用来解析我们的xml的配置文件。就有点类似于我们mymybatis里面的ConfigParse文件。
因为我们有了这个对象,所以我们可以直接去调用里面的pass方法去解析。所以说这个pass里面的方法基本上囊括了我们xml文件中所有配置的标签。都在这里进行一个解析。
我们进入到这个方法里面,就可以看到很多熟悉的标签。而xml文件里面能配置的标签基本上都在这里。
我们再来看一下我们的配置文件长什么样子?
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://masiyi.obmtj0gc1rgs0ho0-mi.oceanbase.aliyuncs.com:3306/test_ob"/>
<property name="username" value="rootmsy"/>
<property name="password" value="Msy18719255298"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
所以说,我们直接看environments 这个标签里面他就是我们要解析的,其他都是我们没有写,所以他直接就return直接跳过了。
我们在这个方法里面看到了。他读取到了xml文件里面数据库相关的信息。他都把它存在这里。之后把configuration的Environment这个属性给他set值。
之后在mapperElement方法里面也解析了我们插面文件里面的mapper节点里面的信息。
这些操作解析完了之后,我们返回了一个DefaultSqlSessionFactory这个实体类,并且把我们刚刚构建了configuration这个类给赋值进去。所以说这个第二行它的目的就是解析我们的xml文件。并把里面所有的信息都解析出来配置给configuration这个类。
最后进入到了这个openSessionFromDataSource方法,这个方法我里面我们可以看到他通过配置对象进行了很多相关的操作,比如说我们创建一个事物,我们构建事物的对象。如果说熟悉我们自己写框架,我们可以看到它也是New了一个执行器出来。最后他把这些串联出来的对象全部封装成一个DefaultSqlSession对象给返回出去。
熟悉我们自定义框架的同学,看到这一步就知道了。他通过 session.getMapper创建出来的对象其实是一个代理对象。他真正执行的方法都是被我们的mybatis全部给代理了。
我们进入findById这个方法里面可以看到它其实走的我是我们invoke方法。
到了这一步,可谓我们终于见到了my buddies的庐山真面目,她执行了invoke方法,里面会最终进入到这个方法,这个方法的作用其实就是解析我们的增删改查。例如我们的xml文件里面写的是select方法,它就会走到对应的枚举类里面去。
相信看到这里的同学已经特别特别特别熟悉了。根据传进来的statement我们可以找到。Configuration里面mappedStatements。对应的MappedStatement
到了这里。学习了我们jdbc连接MySQL的课程时候就非常的熟悉了。看到这些变量和类,这些不就是我们前面第一节课学到的类吗?
最终还是通过execute方法,也就是jdbc里面的方法。执行了SQL。最终获得了结果。
最后根据SQL查询到的结果封装成我们的resultType属性里面对应的类
至此,我们的课程就学完了。我们已经知道了mybatis的最基本的操作大家感兴趣的可以去我的代码仓库里面去查看详细的代码
https://gitee.com/WangFuGui-Ma/my-mybatis。
哦,对了。感谢博学谷的子慕老师提供的mybatis源码(带注释的内容)。
另外如果对Elastic Search感兴趣的话,推荐一下我的专栏,这篇专栏介绍了Elasticsearch的Restful API的入门指南。学习如何使用API进行索引、搜索和分析,包括创建索引、定义映射、添加文档、执行查询等。通过实例和代码片段,快速上手Elasticsearch的Restful API,构建强大的搜索功能。感谢大家支持: