在过去的几周内,我们从
SpringMVC
的配置文件入手,逐步分析了SpringMVC
内部对于一个http
请求处理的全过程,感兴趣的小伙伴可前往专栏SpringMVC流程分析进行查看。
事实上,对于一个web
应用而言,其除了处理http
请求的处理之外,还需要完成的另一件任务就是同数据库
进行交互。提到数据库
交互,你脑海中可能会迅速浮现出CRUD
这几个单词。虽然从某种角度来看,无论多么复杂的业务,其最终对于数据库
的操作,都无法脱离上述的这几个操作。或许,你会觉得只要熟悉了这几行命令就能完成大部分应用的开发,但CRUD
操作背后的故事真的会这样简单吗?我想答案应该是否定的。
事实上,你之所以有这样的想法,很大程度上来说得益于越来越多的orm
框架的出现,从而使得对于数据库复杂的操作逻辑都由框架来帮助我们完成,从而降低了开发web
应用的难度和门槛。
Mybaits
作为当下流行的Orm
框架自发布之初便受到了广大开发者的追捧。那Mybaits
背后究竟为我们做了哪些工作,才使得我们对于数据库
的CRUD
操作变得如此简单呢?
那么,在接下来这段时间内,我们将对Mybatis
源码进行分析讲解,相信坚持看完本专栏你一定会对Mybatis
有一种全新的认识。
听到源码解析可能你想到的作者肯定是全文长篇累牍的贴代码,然后再逐行进行分析。如果你有这样的想法,那可能会让你失望了。
本专栏在写作上面是会对代码内容进行有的放矢的删减,只会保留重要的逻辑以帮助读者更好的理解Mybaits
的处理逻辑。所以可以放心食用。
此外,本专栏创作的初衷也从来不是为了逐行分析Mybatis
源码,因为这样收益甚微。作者更希望能从一种全新的角度带你认识Mybatis
框架,从而帮助读者梳理MyBatis
的主干脉络,加深对于MyBatis
认识和理解。
前言
往往藏着框架的主干逻辑。
在开始分析一个框架之前,我们先来看看Mybatis
框架是如何使用的。因为一些框架的主干逻辑,往往就藏在框架的使用流程中。下面这张图详细的说明了使用Mybatis
的所需要的步骤。
总的来说,如果要使用Mybatis
完成对数据库
操纵,我们需要准备Mybatis
相关的配置文件。具体来看,如果要完成对数据库
操作,则我们必须告知Mybatis
框架,其所需要连接数据库的地址、端口、用户名、密码
等信息。此外,还需要创建映射器接口并编写映射器 xml
文件。
Mybatis
加载流程初探
当配置完使用的Mybatis
所需的配置文件后,接下来要做其实就是将配置
文件的内容告知给MyBatis
框架,在此阶段,通常我们会编写如下的代码信息:
// 加载配置文件
InputStream is = Resources.getResourceAsStream("mybatis.xml");
// 创建sessionFactory对象
sessionFactory = new SqlSessionFactoryBuilder().build(is);
// 获取sqlSession对象信息
SqlSession session = factoy.openSqlSession()
// 构建映射器的代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
// .....调用相关方法信息
(注:这样做的前提是我们已经引入Mybatis
所需的依赖信息)
相信大家接触Mybatis
一定是从上述代码开始的。上述代码背后的逻辑如下:
SqlSessionFactory
对象SqlSessionFactory
获取到一个sqlSession
对象sqlSession
中传入一个Mapper
对象信息,同时获取到一个Mapper
对象Mapper
对象的代理类,调用接口中的方法,从而执行相关sql
语句通过观察上述代码,我们发现在这一过程中的,
处我们会将配置好的xml
信息传入到Mybatis
中。接下来,我们便从此处开始入手,看看在Mybatis
对这些配置文件做了哪些操作。
资源文件加载处理
在处,会通过一句
Resour是es.getResourceAsStream("mybatis.xml")
来获取一个输入流 对象。接下来,我们便进入到其内部看看Resources
的getResourceAsStream
究竟做了完成了哪些工作。
public static InputStream getResourceAsStream(ClassLoader loader,
String resource) throws IOException {
InputStream in = classLoaderWrapper.
getResourceAsStream(resource, loader);
return in;
}
可以看到,此处只是一句平平无奇的资源加载,并没太多复杂处理逻辑。具体来看, 其会通过类加载器的getResourceAsStream
方法返回一个输入流
对象。
接下来,我们将目光转向处,看看
SqlSessionFactoryBuilder
中又完成了哪些处理逻辑。其相关逻辑如下:
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
// 构建XMLConfigBuilder对象
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
// ....省略无关代码
}
可以看到,在处调用的
build
方法内部,其首先会创建一个XMLConfigBuilder
对象,然后再调用其的parse
方法。
配置文件的解析的工具——XMLConfigBuilder
或许你对MLConfigBuilder
这个类很陌生,不清楚其功能是什么。但不要慌,在分析之该类之前,我们不妨先来进行一个总结,看看如果要使用Mybatis
究竟要做那些工作。具体来说,如果要正常使用Mybatis
我们通常需要进行如下两步:
Mybatis
所需的配置文件信息那这个MLConfigBuilder
出现在第几步呢?很明显,它出现第二步中的配置文件解析过程中。如果此时你仍不清楚其功能。别着急,我们再继续接着往下看。我们注意到,在build
方法中,会构建一个XMLConfigBuilder
对象,并将配置文件的输入流
传入。
至此,相信现在你现在大概率已经可以猜出来了这个XMLConfigBuilder
的作用大概率是完成对xml
配置文件的解析。
为了验证这样这一猜想,我们不妨进入到其调用的parse
方法,看看其究竟完成了那些操作。
public Configuration parse() {
// 解析Configuration标签下的内容
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
// 解析configuraion标签下的properties标签
propertiesElement(root.evalNode("properties"));
// 解析configuraion标签下的environments标签
environmentsElement(root.evalNode("environments"));
// ...省略其他无关代码
}
可以看到,在parse
方法中,其会调用parseConfiguration
下configuration
标签的内容。
(注:此处的逻辑主要就是对xml
节点的解析操作,具体细节不再展开详细介绍)
总结
至此,我们便分析清楚了MyBatis
对于配置文件的解析全过程。整体细节如下图所示:
事实上,对于Mybatis
的加载过程来说,其在处理配置文件信息时,首先,会传递配置文件所在位置信息,然后再调用框架提供的SqlSessionFactory
的build
方法便会根据传入路径信息去加载相关的配置文件,并进行解析。而解析的内容会存放到的configuration
之中,进而方便后续组件的使用。
(注:对于图中的Configuration
和SqlSessionFactory
的内容,则会在下一章进行介绍和分析。)