在开始看mybatis源码之前,我们先回顾一下,在mybatis实践篇(一)中的测试类:
public class mybatisTest {
@Test
public void test() throws IOException {
String resource = "configuration.xml";
//将配置文件转换为流文件
InputStream stream = Resources.getResourceAsStream(resource);
//读取配置文件(主要讲解它)
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(stream);
SqlSession sqlSession = build.openSession();
ManMapper mapper = sqlSession.getMapper(ManMapper.class);
Man man = mapper.selectMan("2");
System.out.println(man.toString());
}
我们可以看到,读取配置文件的操作是在SqlSessionFactoryBuilder类中的build方法中完成的,那么我们就从这里开始:
public class SqlSessionFactoryBuilder {
public SqlSessionFactoryBuilder() {
}
public SqlSessionFactory build(Reader reader) {
return this.build((Reader)reader, (String)null, (Properties)null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return this.build((Reader)reader, environment, (Properties)null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return this.build((Reader)reader, (String)null, properties);
}
//Reader读取mybatis配置文件,传入构造方法
//environment读取设置的数据库链接
//properties 读取外部的配置文件
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException var13) {
;
}
}
return var5;
}
public SqlSessionFactory build(InputStream inputStream) {
return this.build((InputStream)inputStream, (String)null, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return this.build((InputStream)inputStream, environment, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return this.build((InputStream)inputStream, (String)null, properties);
}
//inputstream读取mybatis配置文件,传入构造方法
//environment读取设置的数据库链接
//properties 读取外部的配置文件
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//读取配置文件中的信息(重点分析的地方)
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException var13) {
;
}
}
return var5;
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
从SqlSessionFactoryBuilder 的源码源码中可以看出,其实它里面主要就是两个重载的方法:build(Reader reader, String environment, Properties properties) 读取Reader中配置文件信息;build(InputStream inputStream, String environment, Properties properties) 读取InputStream中配置文件信息。
而无论是Reader还是InputStream,都又作为参数传入了XMLConfigBuilder的构造方法中,然后在XMLConfigBuilder类中的成员方法parse()中进行解析。
XMLConfigBuilder的构造方法没有特别的地方,只是对象的初始化、属性赋值。我们重点看一下parse()方法:
public Configuration parse() {
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
//根节点configuration
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
}
parse方法又调用了parseConfiguration
private void parseConfiguration(XNode root) {
try {
//解析properties标签
this.propertiesElement(root.evalNode("properties"));
//解析settings标签
Properties settings = this.settingsAsProperties(root.evalNode("settings"));
this.loadCustomVfs(settings);
this.loadCustomLogImpl(settings);
//解析typeAliases标签(下面的我们就不解释了,到了这里都能看懂了吧)
this.typeAliasesElement(root.evalNode("typeAliases"));
this.pluginElement(root.evalNode("plugins"));
this.objectFactoryElement(root.evalNode("objectFactory"));
this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
this.settingsElement(settings);
this.environmentsElement(root.evalNode("environments"));
this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
this.typeHandlerElement(root.evalNode("typeHandlers"));
this.mapperElement(root.evalNode("mappers"));
} catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
}
}
还记得我们在Mybatis实践篇(四)中罗列过mybatis中的配置文件标签信息,包括顶级标签configuration在内的所有父级标签,如下:
后面的章节中我们会选取几个标签解析的列子进行讲解。