1、配置文件加载
1、类加载器---ClassLoader
具体作用,将我们编译后的class文件加载到我们的jvm虚拟机当中,程序就可以正确运行了,但是jvm启动的时候,并不会一次性加载所有的class文件,而是动态的加载,如果一次性加载那么多jar包的话,那么占用内存会很大
我们的ClassLoader分别有三个
AppClassLoader->ExtClassLoader->BootStrapClassLoader
2、通过Resource读取配置文件
我们的Resource的方法的内部其实还是使用的AppClassLoader加载的我们的mybatis-config.xml文件
在classLoaderWrapper对象当中做了什么事情?
Resource类中使用的是我们的无参new对象,所以它是创建的我们的systemClassLoader对象,AppClassLoader
底层的ClassLoader依次获取流,然后从中我们可以看到它加上了 "/" 这是因为classpath导致,所以加上 / 再尝试一下,看看是否能够拿到
3、SqlSessionFactory创建工作
采用的方式是builder模式创建者模式
SqlSessionFacatory有一个实现类,叫做DefaultSqlSessionFactory
我们的SqlSessionFactory使用build方法的时候内部做出的操作,创建了一个XmlConfigBuilder对象,将我们的获取到的对象流交给了它
parser对象的构造器中需要一个XpathParser对象,解析xml的对象
我们的jdk提供了解析文档的对象
在这里factory所做的操作如下
设置校验规则
设置是否开启命名空间
设置是否忽略注解
设置<!<CDATA[]>>标签是否转文本等
最下面就是将我们new 出来的entityResolver对象也交给它
至于这个entityResolver对象起到什么作用呢?
大家可以看到这里,它是用于去规范我们的规则
config文件有个dtd,专门去指定我们的规则的就比如properties 和 plugins的顺序必须要按照规则来
它是用于处理该工作的对象
如果没有实现该接口的话,那么它读取的就会是config.dtd的规则。有的话则读取本地
从中我们的自定义Mapper文件也是使用的本地的dtd文件
那么在这里之后,回到我们的Xpath就返回了我们的xpathParser对象
接着我们继续初始化我们的Configuration对象
初始化一些我们熟悉常用的东西,比如transcationManager使用的是什么? JDBC
dataSource采用的是 POOLED
配置相关数据完毕了之后
通过.parse方法进行SqlSessionFactory对象的构建
这个parseConfiguration的方法我们可以看到,它从我们的/configuration这个文件中去获取到这些节点进行解析
我们任意挑选一个方法进去看看,比如 enviroments
首先去判断我们的上下文是否为空,如果不是空的话直接获取到我们的config文件中的enviroment默认环境
获取上下文中的子级迭代器
获取到id进行数据的一些获取然后最后将我们的enviroment对象进行建造并返回
在看看扫描mapper的
2、Mybatis动态代理
openSession的操作
获取到我们要操作的环境
里面包含了我们的自定义配置
properties,settings等标签
获取事务需要管理的数据源,以及事务级别,和提交方式
获取执行器,事务级别,执行器类型
最后将我们的SqlSession对象进行返回
DefaultSqlSession构造器
将我们自定义的配置configuration对象交给我们的SqlSession,以及执行器和我们的提交方式
因为我们的默认SqlSession是解决我们的脏读的,所以dirty = false就是代表不能脏读
1、sqlSession.getMapper
getMapper是我们的SqlSession的一个最常用的方法,获取我们的自定义接口实现与我们的documenet标签数,也就是XML进行绑定
它做的操作是什么呢?
用的是我们的configuration.getMapper,也就是用我们的核心配置文件对象去获取这个mapper对象
这个时候我们的Configuration的对象有一个叫做mapperRegistry的注册对象它可以去获取我们的mapper对象
其中我们的MapperProxy实现了我们的 JDK InvocationHandler接口,可以对我们的指定方法进行调用,需要被代理的对象,需要调用的方法
这是当中的细节处理,只要你传入了一个接口进来那么我的成员变量就赋值该接口当你需要创建代理对象的时候就拿它进行传值封装就行
最后创建的代理对象利用的是我们的jdk代理
从中我们给它的参数是
1、我们的类加载器
2、我们的代理类要实现的接口
3、调用方法的代理对象
3、投鞭断流
投鞭断流的典故是在之前的战争时期当中,有个骑马的士兵将骑马的马鞭丢到了河流当中于是我们的河流就被马鞭给拦住了,我们的马就可以直接过河了
到了我们的mybatis这个框架当中也有这样的一个说法,称之为 “mybatis动态代理之投鞭断流”
源码当中可以看到,我们的mapper当中如果没有这一个方法的话,它会把指针指向我们当前this,然后调用自己本身的方法
if(Object.class.equals(method.getDeclaringClass()))
判断该方法是否是Object类定义的方法,如果不是则不走内部逻辑
由此可看这就是我们所称之为的 “动态代理之投鞭断流”
4、代理对象调用mapper方法实现
假设我们接口当中有一个方法,accountMapper.selectByPrimaryKey(Integer id);
它首先会进入到我们的MapperMethod,通过我们的上述代码"投鞭断流",加上我描述的解析mapper节点的图片 + 方法名进行匹配,最后取出这个具体方法去调用对应的sql
5、Mapper的扫描机制
这里我偷懒了,家人们。这里的意思是
1、解析mapper节点
2、获取select | insert等节点标签
3、最后解析resultMap等标签和属性,最后一步是将它添加到我们的configuration当中进行绑定
其中绑定的方式是Map<String,MapperStateMent>
Key=com.cskt.xh.mapper.StudentMapper.selectxxx方法
value=MapperStateMent(对应的sql执行器,内部包含了要运行的sql)
6、总结
随着行业的趋势发展越来越好,想要高薪资不是学习这个框架怎么使用,而是吃透你以后要上班经常用到的技术。
比如说Mybatis这个框架,现在java开发工程师使用的最多的就是mybatis框架做为我们的访问层框架,我们应该去熟悉它的一个运行流程,和代理的机制。