思考,输出,沉淀。用通俗的语言陈述技术,让自己和他人都有所收获。
作者:毅航😜
在专栏Mybatis源码分析中笔者对Mybatis的执行逻辑进行了深入浅出的分析,今天笔者想谈一谈该如何快速构建自己的Mybatis知识主干脉络。毕竟授之以鱼不如授之以渔。
前言
可以说,目前市面上流行的任意一款框架其都必然存在对应输入/输出 的逻辑。换言之,只要我们知晓了该框架输入/输出的具体逻辑,理论上我们就可以熟练的使用任意框架!
当然作为一名有志于成为高级开发的开发者来说,仅仅知晓框架基础使用肯定是远远不够的。因为这样你的可替代性太大了,所以不断的深入分析框架的源码,剖析框架的运行原理成为了我们脱颖而出的一种手段。 可能你会想这些框架源码在工作中会用到吗?说句实话,其实工作中大多数时候是用不到的,用不到那读源码还有什么用呢?
在回答这一问题之前,我们不妨先来思考这样一个问题。那就是面对浩瀚的源码你是否知道该从何处入手?
面对这样一个问题,我想对于大部分刚入行的程序员来说其实很难给出准确答案的。或许,我们的印象中程序员只要会写代码就行了。但事实上真是如此吗?
事实上,对于一名程序员来说,不仅要会写代码更要擅长阅读他人的代码。因为作为程序员的我们不可能每次开发都贯穿产品的整个生命周期,而对于前人代码修修补补是我们工作中所必须面对的。此时如何读懂前人遗留就显得尤为重要,为此具备读懂代码的能力便显得格外重要。
正如我们之前所说的那样,所有的框架其实完全可以视为输入/输出的过程 。换言之,一个框架将输入信息处理为输出结果过程就是该框架的核心逻辑,也即框架的主流程。所以只要分析清楚这条主流程,我们就能快速读懂框架背后的执行逻辑,然后在不断在此基础上深耕。
接下来,笔者便以常见的Mybatis为例来分析,看看我们在读源码时究竟该如何把握住主线。
Mybatis是什么?
看到这问题,我想你肯定会想到如下的话术
MyBatis是一个开源的Java持久化ORM框架,其通过XML或注解实现对象与数据库数据的映射,将SQL语句与Java代码分离,提供灵活的动态SQL和各种参数映射方式。其支持一级和二级缓存,同时其还拥有插件体系以及与Spring等框架集成的事务管理功能。其简单性和易学性使其成为开发者在Java应用程序中执行数据库操作时的首选框架。
我想对于大部分刚接触Mybatis开发者而言一定听过上述这样一段对于Mybatis的概述。不可否认的是,这样的描述确实准确的概括了Mybatis的特点。但其毕竟是标准的"应试"答案。进一步,其实该答案只是对Mybatis框架的一些特性进行介绍,并未触及到Mybatis的原理。
那究竟什么是Mybatis的核心逻辑呢?在回答这一问题之前,我们先来看这样一段代码:
java
public class JDBCDemo {
// .... 省略驱动加载
// 1. 建立数据库连接
Connection connection = DriverManager.getConnection(url, username, password);
// 2. 创建SQL语句
Statement statement = connection.createStatement();
// 3. 执行SQL查询
String selectSql = "SELECT * FROM yourtable";
ResultSet resultSet = statement.executeQuery(selectSql);
//4. 处理查询结果
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
// 处理封装数据
}
}
}
我想如果你Java基础扎实的话,看到上述代码相信你一定会脱口而出,这不就是原生JDBC操作数据库的逻辑吗?如果我继续追问,当Mybatis框架出现后,你还写过这样的代码吗?答案是肯定是否的。
更进一步,为什么Mybatis框架出现后我们不用再通过JDBC原生API来操纵数据库呢?答案其实很简单,因为Mybatis框架内部已经代替我们完成了这些操纵数据库的繁琐了。
至此,Mybatis的主干逻辑其实已经开始变得清晰了。对于Mybatis框架而言,其核心逻辑就是原生 JDBC操作SQL 执行过程。
剖析Mybatis核心逻辑
明确了Mybatis框架的核心主干就是JDBC后,我们再来看我们入门 Mybatis时的经典代码:
java
//<1> 加载配置文件
InputStream is = Resources.getResourceAsStream("mybatis.xml");
//<2> 创建sessionFactory对象
sessionFactory = new SqlSessionFactoryBuilder().build(is);
//<3> 获取sqlSession对象信息
SqlSession session = factoy.openSqlSession()
//<4> 构建映射器的代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
// .....调用相关方法信息
具体来说,上述代码主要做了如下几件事:
-
通过工厂构造器构建一个
SqlSessionFactory对象 -
通过
SqlSessionFactory获取到一个sqlSession对象 -
向
sqlSession中传入一个Mapper对象信息,同时获取到一个Mapper对象 -
获取
Mapper对象的代理类,调用接口中的方法,从而执行相关sql语句
显然,在上述代码中我们使用了Mybatis 为我们提供了两个核心对象,一个是 SqlSession,另一个是 Mapper。
但在分析之前,我们首先要明确一件事那便是在Mybatis中构建SqlSession需要采用工厂模式通过 SqlSessionFactory 来构建。进一步,上述代码中会通过SqlSessionFactoryBuilder 的build方法构建一个一个 SqlSessionFactory。
如果你在深究build方法其内部逻辑不过 Mybatis 内部对于配置文件的解析。
java
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
}
public Configuration parse() {
...
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
其中详细的解析逻辑我们在此便不再赘述,而如下这张图便准确的反映了构建Mybatis内部解析配置文件时的全过程。

当获取到SqlSessionFactory后,便可以通过该工厂类中的工厂方法来创建 SqlSession 对象。进一步,当获取到SqlSession对象后,我们便会构建接口对应的Mapper。更进一步,Mybatis内部获取Mapper的过程如下所示:

在构建Mapper的过程中,我们首先会通过SqlSession中的getMapper方法来获取Dao接口的代理对象。而在Mybatis内部,其会将这部分逻辑委托为Configuration中的mapperRegistry 来完成。最终通过构建一个 MapperProxyFactory的形式来构建Dao接口所对应的代理类。
事实上,由于这部分代码逻辑比较复杂, 在初次学习Mybatis源码时对这部分内容完全可以将这部选择性"忽视",只需知道Mybatis内部最终会通过代理的形式构建一个Dao接口所对应的代理Mapper类即可!
当Mapper通过代理形式生成后,其在执行内部方法时又会回到 SqlSession内部,并委托Mybatis内部一个执行器Executor 组件进行执行。别看其名字起的高大上,其实做的工作不过是JDBC那一套工作罢了!
总结
经过我们这样一分析,你觉得Mybatis还难吗?是不是觉得其本身就是JDBC执行Sql语句的那一套逻辑 ?笔者相信只要顺着这样的思路去分析Mybatis源码你一定可以快速上手Mybatis源码内容,同时当你养成这样分析框架主干的逻辑后,你会发现,日后再去分析类型Spring、SpringMVC等优秀框架时会变的非常轻松!
最后,希望文章对你学习源码有所帮助!当然如果觉得有所收获,不妨点赞+收藏+关注作者!笔者也将持续分享自己在Debug框架源码时的一些所见所想,希望这些内容能真正帮助到你~