每个基于MyBatis的应用都是以一个SqlSessionFactory的实例为中心的。SqlSessionFactory的实例可以通过SqlSessionFactoryBuilder获得。而SqlSessionFactoryBuilder则可以从XML配置文件或一个预先定制的Configuration的实例构建出SqlSessionFactory的实例。
当通过以下方式获得了一个SqlSessionFactory实例的时候:
String resource = "com/test/modul/MyBatis_test/mybatis-config.xml";
InputStream inputStream;
SqlSession sqlSession;
inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, "development1");//这里可以选择不同的environment(在主配置文件中配置)
该sqlSessionFactory实例中有且只有一个成员变量——configuration——类org.apache.ibatis.session.Configuration的实例,该类对应着MyBatis的主配置文件。该类中定义的成员变量基本上和配置文件中的标签一一对应,所以Configuration类在MyBatis中的地位是非常高的,它为该框架在整个应用运行期间提供相关的配置信息。而正因如此,所以在MyBatis框架启动初期就要将配置文件中的信息加载到应用中,并将信息存放在Configuration实例变量中。
接下来让我们探索一下MyBatis是怎么创建SqlSessionFactory实例的?
上面的例子最终会调用SqlSessionFactoryBuilder类的该方法:public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties)
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
上面第三、四行代码非常重要,做的事情很多:配置文件的解析、配置文件信息到Configuration对象的转换等。
先看第三行代码:
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
会创建一个XMLConfigBuilder类的一个实例:
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);//此处创建了一个XPathParser类的一个实例
}
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实例终于开始展露头角啦。这里还只是做了一些准备工作,但是XPathParser实例parser很重要。接着往下看
接着就到了上面的第四行代码:
return build(parser.parse());
然后是下面的代码:
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));//这行代码的背后会给Configuration实例成员赋予配置文件中的信息
return configuration;
}
最后是下面的代码:
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
因此,最后会返回一个DefaultSqlSessionFactory类型的SqlSessionFactory实例,这个实例就是我们上面例子中随后一行所得到的实例。
第一次看源码,讲得很粗糙,如果要详细讲源码的话,这一段会讲很对,其实例子中的最后一行代码就是完成配置信息到代码的转换。今天先看到这儿,明天继续!