思考,输出,沉淀。用通俗的语言陈述技术,让自己和他人都有所收获。
作者:毅航😜
在专栏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
框架源码时的一些所见所想,希望这些内容能真正帮助到你~