1.demo构建--我们做了些什么
首先建立一个demo,通过它来逐步认识mybatis内部是如何工作的。demo地址: https://mybatis.org/mybatis-3/getting-started.html
总结一下这个demo中我们做的事情吧:
1.定义一个mybatis-config.xml配置文件,配置的根节点为configuration,可配置的项有environments, 描述mappers信息的xml文件的位置,以及databaseIdProvider,typeHandler等信息。
2.定义dao接口i.e.BlogMapper ,用来作为生成代理对象的模板。
3.定义namespace与dao接口对应的mapper.xml
4.开始使用mybatis完成数据的crud操作,如图。
具体地:
4.1 读取主配置文件mybatis-config.xml创建输入流is
4.2 以is为资源创建SqlSessionFactoryBuilder这个建造器,没什么好说的,建造工厂用的,单一职责。
4.3 构建SqlSessionFactory,也没啥好说的,就用来创建SqlSession对象。
4.4 factory.openSession(),创建一个与数据库会话的sqlSession对象
4.5 通过sqlSession对象获取到mapper的代理对象
4.6 利用mapper代理对象实现对数据的操作,拿到结果集对应的java对象
4.7 对结果集进行业务逻辑处理。
2.Mybatis做了些什么
简单来说,我们对mybatis的本身、操作数据的方法和方法对应的sql语句做了些配置,mybatis就按照预期完成了对数据的操作,并将结果集封装成了JAVA对象返回给了我们。那这个过程中它需要做哪些事情才能达到这样的效果呢?从我的角度来看至少应当做这些事情:
1.解析配置文件
2.将mapper配置的sql语句和方法对应起来,同时还得生成代理对象来执行方法。
3.管理数据库连接、事务控制.etc
4.sql语句的参数处理
5.将结果集封装成指定的JAVA对象
3.debug看看吧
指定IO源-->读取数据流-->创建SqlSessionFactoryBuilder fb没什么可说的。
先看看fb是如何构建SqlSessionFactory的。
该方法做了两件事情:
1.通过指定的配置源,新建了一个xml解析器。xml解析器用于解析配置,然后生成一个Configuration对象,用来封装配置信息。可以用的配置源有:指定的输入流、系统环境配置以及properties文件。
2.将Configuration对象作为build()方法的参数,构建SqlSessionFactory对象。
3.1 解析配置,创建Configuration对象
mybatis将解析配置文件并创建Configuration对象的工作交给了XMLConfigBuilder,该builder关联了configuration对象。解析分两步:
3.3.1.解析xml文档树。
在配置文件中,
3.3.2.调用parseConfiguraton()方法为configuration设置属性。(重要)
在
然后就开始解析配置文件中的子节点,并为Configuration对象设置属性了。这一步比较关键,因为后续的很多操作都离不开Configuration对象。
在这里以mappers为例,进去看个大概。
我们在configuration中指定mapper的方式有4种,如图。
(参考:https://www.cnblogs.com/dongying/p/4046488.html)
四种方式分别对应的解析方式说明:
1.指定resource,那么直接读取resource指定的xml文件,将其解析为mapper.
之前XMLConfigBuilder完成了部分的Configuration对象属性的封装,现在他将这个对象作为参数传递给了XMLMapperBuilder来对Configuration对象的mapperRegistry属性进行完善。
step1. XMLMapperBuilder去解析这个xml文件的/mapper标签,获取它的namespace,然后解析下面的parameterMap, resultMap,
解析之后的statementMap如图:
step2. 标记该xml已被解析过。this.configuration.addLoadedResource(this.resource);
step3. 完成mapper与namespace的绑定。
到这步的时候,实际上还只是解析出了mapper.xml的信息,但是mapper的代理对象还没创建呢,当然,这一步做完也没有创建出代理对象。但是不创建不要紧,总得给我个能创建代理对象的东西出来吧,到时候我根据mapper的namespace一查,就可以知道我该创建一个怎样的对象。那么给我个什么呢?想想创建对象需要干嘛?类加载,分配空间,实例化对象,初始化对象。那就简单了,给我一个这个类的Class对象好了。
所以这一步要干的事情就是通过类加载器,完成类的加载的加载过程,获取它的类型。
现在我知道他是什么类型了,我需要把他存起来吧,存哪里呢?mapperRegistry。所以config.addMapper()方法实际上把责任交给了mapperRegistry来完成类型的注册。
mapperRegistry是一个hashMap,怎么就存一个Class对象type呢,这不对劲。实际上是以type:MapperProxyFactory(type)的形式存放的。这个proxyFactory的构造方法非常简单,就是将type作为属性放了进去。它的作用嘛,显然是等以后需要用到该mapper接口的代理对象时,用来创建代理对象。(这点等后面的文章细说)
2.如果是指定包扫描的方式,获取包名,扫描包下的所有mapper,加载为class对象,存入configuration.mapperRegistry内。
实际上到了最后,还是得遍历class数组,然后用mapperRegistry.addMapper(type)完成注册。
step4. 完成到目前为止还没有解析完的resultMap,statement...
原因是:resultMap的extends的没有解析,等待其余resultMap都解析完毕再次调用ResultMapResolver的resolve方法解析。此时若从configuration还得不到id为extends的ResultMap则忽略,因为parsePendingResultMaps中捕获了IncompleteElementException并啥也不做。ref:https://blog.csdn.net/shenchaohao12321/article/details/79841046
3.1.3 小结
本节描述了解析配置,创建Configuration对象的过程。其关键步骤在于创建Configuration对象,并为该对象完成属性赋值。
以mappers相关属性的设置为例,讲述了从xml文件解析mapper的parameterType、resultTyle、sql语句等信息,并与dao接口完成绑定的过程。
3.2 构建SqlSessionFactory对象
没什么好说的,直接调用构造方法