MyBatis源码解析——获取SqlSessionFactory方式
作者:rz_0212
MyBatis源码解析_获取SqlSessionFactory
我们都知道,在Mybatis中,对数据库的增删改查,实际上是由SqlSession来操作的,而SqlSession又是从SqlSessionFactory中得到的,那么问题来了,SqlSessonFactory是如何获得的呢?我们一起来解读一下Mybatis是如何加载配置文件,从而获取SqlSessionFactory的。
首先从Resources.getResourceAsReader(path)
传入我们mybatis全局配置文件得到一个输入流InputStream,这里用Reader来接收。然后new一个SqlSessionFactoryBuilder对象,这是干嘛呢,这个对象里有一个build(Reader)方法,可以将我们传入的Reader,经过一系列的解析过程,返回给我们一个SqlSessionFactory实例,这样我们就得到了想要的SqlSessionFactory了,估计要是这么就结束了,读者会不会打死我呀(哈哈)。
所以我们就详细说一下中间的解析过程。
进入到SqlSessionFactoryBuilder.build(Reader)方法中
它会再次调用build(Reader,environment(默认是null),Properties(默认是null))方法,在这里,根据我们传入的参数先new出一个XMLConfigBuilder对象,称为parser(就是个解析器),然后parser调用它的parse()方法,parse()方法中有一个parseConfiguration(parser.evalNode("/configuration"))方法,我们知道mybatis的全局配置文件是以configuration作为根节点的,而且各个子节点是有严格顺序的,这里就是找到configuration根节点,来分别解析根节点下的每个子节点,然后将解析结果放在一个Configuration中。
解析节点是调用XpathParser.evalNode(root , expression),返回一个XNode,当作参数,放在一个**Element(XNode)方法中去处理节点里每一个信息。这里我们选一个mapperElement(root.evalNode("mappers"))来看看,它是如何解析mappers这个子节点的。
进入到mapperElement(XNode)方法后
先去判断传入的节点是否为null,不为null则解析XNode下的每一个孩子节点,(在mappers标签下,可以插入两种子节点,一种是package,这种做法,要求接口和xml文档在同一个包下,另一种是mapper,mapper节点里有三种属性,分别是resource,url,class,至多只能选一种)。
这里我我们来判断子节点名字是否为"package",如果是,将package节点中的name取出,调用Configuration.addMappers(mapperPackage)方法,实际上调用MapperRegistry.addMappers(packeagename)方法,在这里,又new出了一个ResolverUtil<Class<?>>对象resolverUtil,它可以通过find()方法,找到该包下所有的所有的class或是别的文件,然后筛选出所有.class文件(不是class文件不要),如果是接口的话(不是接口不管),new出一个MapperAnnotationBuilder对象parser(实际上也是个解析器),调用parser.parse()方法,加载与接口名相同的XML文件,保存在configuration中。
如果子节点名字不是package
则取出"resource"、"url"、"class"等属性,分别进行判空,如果属性resource中有值,先将resource所对应的xml文件给转成一个InputStream,再new出一个XMLMapperBuilder(inputStream,configuration,resource)对象mapperParser(这里也是个解析器),调用parse()方法,对接口里所对应的XML文件去解析,具体解析过程和解析mybatis全局配置文件比较类似。
在解析每一个增删改查标签,都会new一个mappedStatement对象statement(这里是通过它的静态内部类Builder来new的),相当于一个MappedStatemet就代表了一个增删改查的详细信息 ,同样MappedStatement也保存在Configuration中。
对于url中有值,过程和resource那个一样,这里不作讲述。对于mapperClass中有值,通过全类名反射,拿到对应的接口,调用configuration.addMapper(mapperInterface)方法,具体过程和package那个一样,也不再讲述。
经过一系列的解析,终于完成了
mappers节点的所有信息也都保存在Configuration中。这个时候回到SqlSessionFactoryBuilder中,将返回的Configuration对象作为参数,调用它的build(configuration)方法,这里是关键的一步,此时根据configuration,new出了一个DefaultSqlSessionFactory对象返回给我们。
我们来看一下DefaultSqlSessionFactory这个类有啥特别的呢,它实现了SqlSessionFactory接口,这个接口里有很多openSession()的重载方法,原来如此,这里我们终于得到了SqlSessionFactory,也就是一个DefaultSqlSessionFactory对象,这个对象里保存着我们的Configuration,而Configuration里又保存着我们全局配置文件里的所有信息,以及**mapper.xml文件里所有信息。
如图所示。
好啦,SqlSessionFactory获取过程就讲到这里啦,想要了解更多细节的童鞋,也可以自己去一步步debug,跟踪源码,了解整个过程
用MyBatis的配置文件获取SqlSessionFactory
import java.io.IOException; import java.io.Reader; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class GetSqlSessionFactory { private static SqlSessionFactory sqlSessionFactory; static{ String rs="mybatis-config.xml"; try { Reader reader=Resources.getResourceAsReader(rs); SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder(); sqlSessionFactory=builder.build(reader); //sqlSessionFactory.getConfiguration().addMappers("com.hengtian.mapper"); } catch (IOException e) { e.printStackTrace(); } } public static SqlSessionFactory getInstance(){ return sqlSessionFactory; } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
- 解析Mybatis SqlSessionFactory初始化原理
- mybatis初始化SqlSessionFactory失败的几个原因分析
- 使用Mybatis-Plus时的SqlSessionFactory问题及处理
- Mybatis SqlSessionFactory与SqlSession详细讲解
- 详解Mybatis核心类SqlSessionFactory的构建
- Mybatis中自定义实例化SqlSessionFactoryBean问题
- MyBatis-plus报错Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required的解决方法
- 使用Mybatis时SqlSessionFactory对象总是报空指针