从mybatis3用户指南(翻译版)中我们可以看到下面这段话:
每一个 MyBatis的应用程序都以一个SqlSessionFactory对象的实例为核心。
SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder 对 象 来 获 得 。
SqlSessionFactoryBuilder 对象可以从 XML 配置文件,或从 Configuration 类的习惯准备的实例中构建 SqlSessionFactory 对象。
由此可见SqlSessionFactory 在mybatis项目中是尤为重要的,本篇主要研究构建 SqlSessionFactory 对象的第一种,即通过XML配置文件构建 SqlSessionFactory 对象。
用户指南的作者也为我们提供了demo:
① Reader reader = Resources.getResourceAsReader("configuration.xml");
② SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
第①行代码,我们通过方法名即可知道,无外乎就是把配置文件读入到流中,构建一个Reader对象,存储配置文件中的信息。
接下来主要看一下第二行代码。
这行代码主要涉及到一个接口,两个对象实例,一个方法。
一、先看一下SqlSessionFactory 接口
这个接口主要有两个方法:SqlSession openSession()及其重载方法和Configuration getConfiguration(),这里又涉及到一个接口和一个类,再来看一下这两个类。
(1)SqlSession :该接口提供了大量的数库操作方法,创建、关闭连接,增删改查,以及事务提交、回滚等方法;
创建SqlSessionFactory 的一个主要原因就是该接口可以实例化SqlSession 对象,而SqlSession 使我们操作数据库的核心接口,关于SqlSession 的具体代码研究,在后续继续学习,目前先知道这个接口的主要功能即可
(2)Configuration:该类主要包含了客户端环境信息,即配置文件信息,后续详细研究该类
二、Reader reader对象,该对象为配置文件信息流化后的类。
三、SqlSessionFactoryBuilder
该类只有一个build(Reader reader)方法和多个重载方法,下面来研究一下这个build方法。
该类中的所有build重载方法,底层都是调用下面这个方法
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
其中new XMLConfigBuilder(reader, environment, properties)调用如下方法:
public XMLConfigBuilder(Reader reader, String environment, Properties props) {
this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
}
而new XPathParser(reader, true, props, new XMLMapperEntityResolver())是为了构建一个XPathParser实例,构建这个对象的目的是将reader解析为Document存放在XPathParser的document属性中。
再看看整个XMLConfigBuilder的构造方法又做了些什么:
private XMLConfigBuilder(XPathParser parser, String environment, Properties props)
{
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
很明显,就是创建一个新的Configuration,并将包含reader全部信息的parser赋给自己的属性值。这时候可以看到这个XMLConfigBuilder含有两个关键属性
1、一个新的Configuration实例
2、一个包含已经将reader转换为Document的XPathParser 实例
既然已经知道了这个XMLConfigBuilder有什么能力,再来看看他能做什么,可以通过名称来猜一下,XMLConfigBuilder估计也就是build一个Configuration。为了证实我的猜想,再来开一下parser.parse()这个方法:
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
这个方法最终返回了一个configuration对象,上面已经看到configuration是一个新new的对象,那么在返回之前执行的parseConfiguration(parser.evalNode("/configuration"))这行代码,就是对configuration进行一些配置,事实上该方法才是真正的核心方法,这个方法将configuration.xml中各个标签值实际的配置到了系统中,包括数据库的连接、sqlMaps的加载等等。不过对于该方法暂时只需知道功能即可,具体实现日后再说。
现在知道了return build(parser.parse())这个方法实际上是build(configuration)
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
我们可以看到最后放回的是一个DefaultSqlSessionFactory,而DefaultSqlSessionFactory是SqlSessionFactory的实现类,这样我们就得到了SqlSessionFactory。
最后在传一张自己画的流程图